难度
初级
学习时间
30分钟
适合人群
零基础
开发语言
Java
开发环境
- JDK v11
- IntelliJ IDEA v2018.3
提示
本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
1.多态与构造方法
构造方法在多态中的初始化顺序是怎样的?
演示:
请用类来描述以下场景,一栋房子里有人、猫和狗。
注:如有公共部分请提取到父类。
代码:
People类:
Animal类:
Cat类:
Dog类:
Home类:
Main类:
结果:
这个执行结果是和你想象中一样吗?
最先打印的是People构造方法,不难解释:
当父类构造方法执行完毕之后,子类的实例变量就会按照声明的顺序优先于构造方法初始化。这里Home的父类是Object。
我们再往下看,打印的是“Animal 构造方法”,这个也不难解释:
Home类里面继续往下初始化,就到了Cat,Cat在初始化时,就先调用父类的构造方法,也就是Animal的构造方法,所以这里会优先打印“Animal 构造方法”。最后,父类构造方法执行完毕,执行子类实例变量初始化,子类构造方法:
Cat类中并没有自己的实例变量,执行到构造方法时打印“Cat 构造方法”:
再往下看运行结果,打印的又是“Animal 构造方法”,原因还是一样,我们Home类里面初始化到了Dog:
Dog继承Animal,优先调用父类构造方法,所以打印“Animal 构造方法”,其次是当父类构造方法执行完毕之后,再初始化子类实例变量和构造方法:
Dog类中没有实例变量,于是就打印“Dog 构造方法”:
到运行结果的最后,就是初始化Home自己了:
打印“Home 构造方法”:
2.当构造方法里面有多态时
演示:
请编写一个子类和父类。
父类中有一个实例方法,子类重写了这个实例方法。
子类中有一个私有的实例变量。
子类在重写的实例方法里面调用了这个实例变量。
父类在构造方法中调用了实例方法。
请观察程序运行结果。
代码:
People类:
Student类:
Main类:
结果:
请大家仔细观察运行结果。首先,我们来看打印的第一行“People 构造方法”:
子类Student继承自父类People,优先初始化父类People,调用父类People构造方法:
打印“People 构造方法”。
再往下执行,调用say方法,请问:是调用的People类里面的say方法还是子类Student里面的say方法?
从运行结果来看,调用的是子类里面的say方法。为什么?
这是由于子类重写了父类say方法,覆盖造成的。如果要调用构造方法内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。也就是当父类构造方法调用动态绑定方法时,调用的是被重写的方法。所以打印“Student say: null”。
最后子类Student初始化完毕,打印“Student 构造方法: Tom”。
3.小心:在构造方法内部调用动态绑定方法
将上节程序进行小的改动,其他类不变,修改子类Student:
就是将“name”改为了“name.length()”,然后运行看看:
错误信息:
文字版:
People 构造方法
Exception in thread "main" java.lang.NullPointerException
at lab.Student.say(Student.java:28)
at lab.People.<init>(People.java:13)
at lab.Student.<init>(Student.java:18)
at main.Main.main(Main.java:9)
造成此次程序运行错误的原因就是父类的构造方法中调用了动态绑定方法,而该方法被子类重写了,里面还调用了为初始化完成的成员方法,触发空指针异常。
总结
- 如果要调用构造方法内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。
- 不要在构造方法里面调用动态绑定方法。
至此,Java中多态与构造方法相关内容讲解先告一段落,更多内容请持续关注。
答疑
如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。
上一章
下一章
“全栈2019”Java第五十八章:多态中方法返回类型可以是子类类型
学习小组
加入同步学习小组,共同交流与进步。
- 方式一:关注头条号Gorhaf,私信“Java学习小组”。
- 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划
关注我们,加入“全栈工程师学习计划”。
版权声明
原创不易,未经允许不得转载!