22

我试图理解 Java 的多态性,并且我有一个关于向下转换对象的问题。假设对于这个例子,我有两个继承自超类 Animal 的子类 Dog 和 Cat

据我了解,向下转换对象的唯一方法是该对象是否已经是好的类型,如下所示:

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

4 回答 4

9

如果要创建可能因非本地条件而异的类型的实例,请使用抽象工厂(如《设计模式》一书中所述)。

以最简单的形式:

interface AnimalFactory {
    Animal createAnimal();
}

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

另请注意,引用的静态类型和对象的动态类型之间存在差异。即使你有一个Animal引用,如果原始对象是 a Dog,它的行为仍然像 a Dog

于 2010-10-27T12:33:45.547 回答
3

您应该只转换为对象实际上是的类,因此如果您有Dog扩展的 a,Animal您可以将其转换为 an Animal(因为它是一个),但您不应该将 anAnimal转换为 a Dog,因为并非所有Animals 都是Dogs。该类Dog很可能具有该类未实现的额外字段,Animal因此强制转换没有意义(您将这些值初始化为什么?)。

于 2010-10-27T12:32:14.933 回答
1

Java 是一种强类型语言,这意味着您只能将对象转换为它扩展的类型(超类或接口)。

即使您“伪造它”,例如复制所有类的方法和字段,您也不能将对象转换为它不扩展的类型。

public class Foo{

    public String phleem;

    public void bar(){

    }

}

public class Bar{

    public String phleem;

}

public interface Baz{

    public void bar();

}

鉴于上面的代码,您不能将Foo对象转换为 aBar或 a Baz,尽管类结构似乎暗示您可以。不涉及继承,因此ClassCastException抛出 a 。

于 2010-10-27T12:29:06.937 回答
0

在这里,您正在谈论向下转换,因此在这种情况下,始终应将超类用作引用,并且应将子对象指向它。这个usd基本上是工厂模式。

于 2010-11-04T09:40:12.720 回答