起因
晚上无聊水群的时候,看见群友在讨论Java多态,作为学习Java两个月半的练习生,我便颇有信心的上去讨论,结果,不出所料的难住我了.
疑问1
public class Animal {
}
public class cat extends Animal {
public void ls(){}
}
public static void main(String[] args) {
Animal animal = new cat();
Cat cat = (Cat) animal;
animal.ls();
((Cat) animal).ls();
cat.ls();
}
观察上面的语句,请问哪一句会报错呢?
答案是animal.ls()会报错
为什么呢?
- 变量类型:变量
animal
在这里被声明为Animal
类型,这意味着通过animal
引用能够访问的成员(方法和属性)仅限于那些在Animal
类中定义的或者被Animal
类继承的成员。 - 实例对象:尽管
animal
变量是Animal
类型,但它实际上指向的是一个Cat
类的实例。这表示在运行时,如果Cat
类覆盖(Override)了Animal
类中的任何方法,那么通过animal
调用这些方法时,执行的是Cat
类中的实现。
这种情况下体现了Java的多态性。多态允许你使用一个接口类型引用指向它的任何一个实现类的实例,或者使用一个父类类型的引用指向其任何一个子类的实例。因此,虽然 animal
是 Animal
类型,但具体的行为(如方法调用)会根据实际创建的对象(这里是 Cat
)来决定。
疑问2
那么到底什么是向上转型和向下转型呢
public static void main(String[] args) {
Animal animal = new Cat();//向上转型
Cat cat = (Cat) animal;//向下转型
animal.ls();
((Cat) animal).ls();//显式向下转型
Cat.ls();
}
向上转型:
定义:向上转型是将一个子类的对象自动转换为父类类型的引用的过程。在Java中,这是自动且安全的,不需要显式转换。向上转型意味着将一个具体的、特定类型的对象视为其更通用、更抽象的父类型,从而允许更加灵活和泛化的操作。
这里有一个很典型的应用,比如在方法传参的时候,子类变量能被当作父类变量传入形式参数里
向下转型(Downcasting)
定义:向下转型是将一个父类类型的引用显式转换为其真正的子类类型的引用。这是必需手动进行的,并且可能存在风险,因为如果转换的目标类型并非引用实际指向的对象类型,就会在运行时抛出ClassCastException
异常。
当你写 ((cat) animal)
时,这一步是显式向下转型。你告诉编译器你确信 animal
引用实际指向的是一个 Cat
对象,因此你想将其转换回 Cat
类型,以便访问 Cat
类中定义的方法,比如 ls()
。
看完了定义之后,我有一个疑问
Animal animal = new Cat();
怎么会是向上转型呢,明明是父类变量animal变成了子类,Cat类,难道不应该是向下转型吗??
其实这里只是我们理解的方向错了,这里的意思是创建了一个 Cat
类的实例(子类)并将其赋值给 Animal
类型的变量(父类),将一个更泛化的类型来引用一个更具体的对象。这允许程序以更通用的方式来处理对象。