如何将Java对象向下转换?

24

我正在尝试理解Java的多态性,我有一个关于向下转型对象的问题。 假设我们有两个子类Dog和Cat,它们都继承自超类Animal。

据我所了解,向下转型对象的唯一方法是如果此对象已经是正确类型,则可以这样做:

Animal a = new Dog();
Dog d = (Dog) a;

这个有效吗?

但是如果我想创建一个普通的动物,而不知道它会成为什么,并在我知道后将其转换,我该怎么做?

Animal a = new Animal();
Dog d = (Dog) a;

这会在运行时抛出ClassCastException异常,对吗?

我找到的唯一方法是创建一个新的Dog构造函数,通过普通动物来创建一只狗:

Animal a = new Animal();
Dog d = new Dog(a);

使用

public Class Dog extends Animal{
   public Dog(Animal a){
      super(a);
   }
}

所以我的问题是,我应该怎么做呢?

  • 我是否在用最好的方式进行操作?
  • 如果必须这样做,那么我是否本来就不应该这样做,这意味着我的程序设计不好?
  • 是否有更好的方法我没想到?

非常感谢! nbarraille

4个回答

11
如果您想创建一个可能因非局部条件而变化的类型实例,请使用抽象工厂(如《设计模式》一书中所述)。
简单来说:
interface AnimalFactory {
    Animal createAnimal();
}

class DogFactory implements AnimalFactory {
    public Dog createAnimal() {
        return new Dog();
    }
}

还要注意引用的静态类型和对象的动态类型之间存在差异。即使您有一个Animal引用,如果原始对象是Dog,它仍然表现得像一个Dog


4
您应该只将对象转换为其真正的类,因此如果您有一个扩展了AnimalDog,则可以将其转换为Animal(因为它是一个Animal),但您不应该将Animal转换为Dog,因为并非所有Animal都是DogDog类可能具有Animal类未实现的额外字段,因此类型转换没有意义(如何初始化这些值?)。

1
Java是一种强类型语言,这意味着你只能将一个对象转换为它所扩展的类型(可以是超类或接口)。
即使你“假装”,比如复制所有类的方法和字段,你也无法将对象转换为它不扩展的类型。
public class Foo{

    public String phleem;

    public void bar(){

    }

}

public class Bar{

    public String phleem;

}

public interface Baz{

    public void bar();

}

给定上述代码,尽管类结构似乎暗示可以这样做,但你不能将一个Foo对象转换为BarBaz。由于没有涉及继承,因此会抛出ClassCastException异常。

0

在这里,您正在谈论向下转换,因此在这种情况下,始终应该使用超类作为引用,并指向子对象。这基本上是在工厂模式中使用的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接