Java 将子类对象强制转换为超类
我有一些关于上抛/下抛的问题 我创建了一个抽象的超类动物,子类狗和子类大狗。我还给出了动物的抽象方法,并在狗和大狗中重写了它Java 将子类对象强制转换为超类,java,class,casting,subclass,superclass,Java,Class,Casting,Subclass,Superclass,我有一些关于上抛/下抛的问题 我创建了一个抽象的超类动物,子类狗和子类大狗。我还给出了动物的抽象方法,并在狗和大狗中重写了它 abstract public class Animal { abstract public void greeting(); } public class Dog extends Animal { @Override public void greeting() { System.out.println("Woof!"); } }
abstract public class Animal {
abstract public void greeting();
}
public class Dog extends Animal {
@Override
public void greeting() {
System.out.println("Woof!");
}
}
public class BigDog extends Dog {
@Override
public void greeting() {
System.out.println("Woow!");
}
}
现在,我的测试代码:
public class TestAnimal {
public static void main(String[] args) {
Animal animal2 = new Dog();
Animal animal3 = new BigDog();
// Downcast
Dog dog2 = (Dog) animal2; //cast Animal class to Dog class, legit
BigDog bigDog2 = (BigDog) animal3; //cast Animal to BigDog, legit;
Dog dog3 = (Dog) animal3; //Animal Class contains BigDog cast into Dog?
dog2.greeting();
dog3.greeting(); //in which class the method is called?
}
}
我理解超类/子类之间的关系以及cast是如何工作的。然而,我的问题是,你能把一个超类转换成一个特定的子类吗?你知道中间有一个类吗?例如,如果我有一个动物类对象包含一个BigDog对象,我可以将该对象强制转换为Dog吗?如果BigDog中有一些方法在Dog中不存在呢
简而言之,可以肯定地说,超类对象是子类对象,但为什么可以反转呢
仔细想想 我猜是这样的:我要求JVM将动物类引用转换为Dog,并将新的Dog引用链接到BigDog对象,而不是真正转换BigDog对象 所以我可以调用该Dog引用(到BigDog)上的所有Dog和Animal方法,但是没有一个BigDog方法,除非它在BigDog中被重写 Java在调用方法时检查的是:引用(DOG)是否有引用,对象(BigDog)是否有重写。否则,将调用BigDog方法
有人能证实我的猜测吗?没有签名与这些方法调用匹配的方法:
dog2.greeting(dog3);
dog3.greeting(dog2);
因此,这几乎是一次编译失败
您需要了解动态方法调度
这里有几个链接,请浏览。
如果我有一个动物类对象包含一个BigDog对象,我可以将该对象强制转换为Dog吗?如果BigDog中存在Dog中不存在的方法怎么办?
您将得到编译器错误。因为您不能调用未在父类中声明且使用父引用在子类中声明的方法,请首先更正源代码,这样它将编译。方法的正确使用:
dog2.greeting()代码>和dog3.greeting()代码>或添加方法<代码>公共无效问候语(动物)代码>
dog3.greeting()代码>-调用dog3
的方法greeting()
dog3
与animal3
具有相同的引用animal3
引用了BigDog
,因此方法greeting()
被调用到类BigDog
,输出为Woow代码>
当您从classAnimal
继承Dog
时,则classDog
具有classAnimal
的所有方法,您始终可以强制转换到特定的子类,除非编译器足够聪明,能够确定您的强制转换是不可能的
强制转换到子类的最佳方法是检查是否可以执行:
if ( doggy instanceof BigDog ) {
doSomethingWithBigdog( (BigDog) doggy );
} else if ( doggy instanceof SmallDog ) {
doSomethingWithSmalldog( (SmallDog) doggy );
} else {
// Neither a big dog nor a small dog
}
...
private void doSomethingWithBigdog( BigDog dog ) {
...
}
private void doSomethingWithSmalldog( SmallDog dog ) {
...
}
记住铸造是邪恶的。有时是必要的,但通常(并非总是)可以通过在基类上实现方法来设计,或者不将Dog分配给动物变量,而是将其保留为Dog。方法的正确用法:dog2.greeting()代码>和dog3.greeting()代码>或添加方法<代码>公共无效问候语(动物)代码>。然后源代码将被编译。很抱歉,复制和粘贴的人忘记了更改参数。这是静态和动态类型变量的一个很好的例子。有好几本书/几条线索说明了我在复制和粘贴时的错误。原始代码必须为methods.ok。浏览答案中的链接。将调用dog引用所引用的对象的问候语()。