例题:
(单选题) 下面代码的输出是什么?
- public class Base {
-
- private String baseName= "base";
- public Base(){
- callName();
- }
-
- public void callName(){
- System.out.println(baseName);
- }
-
- static class Sub extends Base{
- private String baseName = "sub";
- public void callName(){
- System.out.println(baseName);
- }
- }
-
- public static void main(String[] args){
- Base b = new Sub();
- }
-
- }
A.null
B.sub
C.base
答案:A
为了能更好的分析代码运行过程, 做原有代码做一些变动如下:
- public class Base {
- private String baseName= "base";
-
- public Base(){
- System.out.println("Constructor Base : " + baseName);
-
- System.out.println("before Base callName() -----" );
-
- callName();
-
- System.out.println("after Base callName() -----" );
- }
-
- public void callName(){
- System.out.println("& " + baseName);
- }
-
- static class Sub extends Base{
- private String baseName = "sub";
-
- public Sub(){
- System.out.println("Constructor Sub : " + baseName);
- }
-
- @Override
- public void callName(){
- System.out.println("# " + baseName);
- }
- }
-
- public static void main(String[] args){
- new Sub();
- }
-
- }
此时 main 方法内 new Sub();
输出结果:
- Constructor Base : base
- before Base callName() -----
- # null
- after Base callName() -----
- Constructor Sub : sub
再将main方法做如下变动:
- public static void main(String[] args){
-
- Base b = new Sub();
-
- b.callName();
- }
输出结果:
- Constructor Base : base
- before Base callName() -----
- # null
- after Base callName() -----
- Constructor Sub : sub
- # sub
综上所述, 此时运行的是子类Sub的callName() 方法,
new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null
先成员变量再构造方法,先父类再子类
多态表现:有同名方法执行子类的
执行 Base b = new Sub();时,由于多态 b编译时表现为Base类特性,运行时表现为Sub类特性,
Base b = new Sub();不管是哪种状态都会调用Base构造器执行 callName()方法;
执行方法时,由于多态表现为子类特性,所以会先在子类是否有 callName();
而此时子类尚未初始化(执行完父类构造器后才会开始执行子类),
如果有 就 执行(此时, 因为还没有调用子类构造函数, 所以子类的 baseName 输出为 null),没有再去父类寻找。