我正在尝试理解Java的多态性,我有一个关于向下转换对象的问题。 让我们说这个例子我有两个继承自超类Animal
的子类Dog和Cat根据我的理解,向下转换对象的唯一方法是,如果此Object已经是好的类型,如下所示:
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
答案 0 :(得分:9)
如果要创建可能因非本地条件而异的类型实例,请使用Abstract Factory(如“设计模式”一书中所述)。
以最简单的形式:
interface AnimalFactory {
Animal createAnimal();
}
class DogFactory implements AnimalFactory {
public Dog createAnimal() {
return new Dog();
}
}
另请注意,引用的静态类型与对象的动态类型之间存在差异。即使您有Animal
引用,如果原始对象是Dog
,它仍然表现得像Dog
。
答案 1 :(得分:3)
您应该只转换为该对象确实存在的类,因此,如果您有Dog
扩展Animal
,则可以将其转换为Animal
(因为它是一个)但是您不应该将Animal
投射到Dog
,因为并非所有Animal
都是Dog
。 Dog
类可能有额外的字段没有Animal
类实现,所以演员表没有意义(你将这些值初始化为什么?)。
答案 2 :(得分:1)
Java是一种强类型语言,这意味着您只能将对象转换为它所扩展的类型(超类或接口)。
即使你“假装”,例如复制所有类方法和字段,你只是不能将对象强制转换为它不扩展的类型。
public class Foo{
public String phleem;
public void bar(){
}
}
public class Bar{
public String phleem;
}
public interface Baz{
public void bar();
}
鉴于上述代码,您无法将Foo
对象转换为Bar
或Baz
,尽管类结构似乎暗示您可以。没有涉及继承,因此抛出ClassCastException
。
答案 3 :(得分:0)
这里你谈论的是向下转换,所以在这种情况下,总是应该使用超类作为引用,并且应该指向子对象。 这个usd基本上是工厂模式。