在讲Java的继承和重写时,我们只使用过父类变量创建父类对象,子类变量创建子类对象,重写后,子类对象调用子类重写后的方法,那么,当我们拿一个父类变量去创建一个子类对象时,会出现什么呢?当我们去调用父子类共有的方法时,调用的方法是重写前的还是重写后的呢?
本篇就讲一讲Java中的多态。
正如上述,Java程序中,当我们用父类变量创建的子类对象去调用一个子类重写过的方法时,多态就出现了。
创建父类:
创建子类:
再创建一个类:
有代码之,在earth类中创建子类对象,该对象调用方法时,毋庸置疑,调用的是重写后的方法:
之后,让我们观察这样一条语句:
double a = 9;
有我之前的文章Java的数据类型值,这是自动类型转换,9默认是int型,所以能转换成double型。
接着,我们在Earth类中加入如下代码:
Mammal mammal1 = new Whale(); //自动类型转换(小范围给大范围):父类类型的变量指向子类创建的对象;对象上转型 new Whale() 上转型对象
mammal1.move(); //两个状态:表面调用的是父类的方法;但执行时由于mammal1中存的是子类创建的对象,所以调用的是子类的方法
这正是用父类变量创建子类对象,再来观察运行结果:
可见,mammal1是一个父类变量,但因为该变量内存的是一个子类对象的地址,因此根据Java中对象调用方法的原理,mammal1调用了子类方法,这就是Java中的多态,直观来讲,因为“ Mammal mammal1 = new Whale(); ”语句等号两端包含两种类,所以称之为多态。
Java引用变量有两种类型,分别是编译时类型和运行时类型:编译时类型由声明该变量时使用的类型决定;运行时类型由实际赋给该变量的对象。如果编译时类型和运行时类型不一致,就可能出现所谓多态(因为当子类方法没有被重写时,那就不存在多态)。
所以就会有以下两个判断:
//如果编译时类型与运行时类型相同,则一定不会出现多态;√
//如果编译时类型与运行时类型不相同,则一定出现多态;×
那么问题来了,出了调用子类重写的父类方法,我们能否调用子类新增方法呢?
(1)在子类中新增breathe方法,并在earth类中加入调用代码“mammal1.breath();”:
public class Whale extends Mammal {
@Override
public void move() {
System.out.println("鲸鱼用鳍游动......");
}
public void breathe() {
System.out.println("用肺呼吸");
}
}
可见,出现编译错误。
这就说明,上转型对象无法直接调用子类中子类中新增方法,这时,我们就需要用到对象下转型。
改写代码:
其中“Whale whale1 = (Whale)mammal1;”语句类似Java中数据类型的强制转换。
则编译器不再报错。
注:(1)对象下转型的前提是有上转型对象,否则编译器正常,但运行出错;
(2)上转型对象与下转型对象中村的地址是相同的
这就是Java中的多态。