先看一道Java面试题:
求这段程序的输出。
解答此题关键在于理解和掌握类的加载过程以及子类继承父类后,重写方法的调用问题:
从程序的执行顺序去解答:
1.编译;当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class 文件加载到内存
2、Base base= new Sub():
声明父类变量base对子类的引用,JAVA类加载器将Base,Sub类加载到JVM(Java虚拟机);
3、JVM为Base,Sub 的的成员开辟内存空间
此时,Base 和Sub类中的值为null;
4、new Sub();
这个时候会调用Sub类的隐式构造方法,
Sub的构造方法本质为:
public Sub(){
super();// 调用父类的构造方法。必须在构造方法中的第一行,为什么呢?这是因为在一些程序的升级中,要兼容旧版本的一些功能,父类即原先的一些初始化信息也要保证 //被执行到,然后执行当前
baseName = "sub";//子类字段初始化
}
new Sub()执行到super()这行代码也就是跑到父类中去执行了,我们跳转到父类中的无参构造方法中执行,最后执行Sub()中的baseName = "sub";
5、public Base() ;
父类无参构造方法的本质为:
public Base(){
baseName= "base";//父类字段初始化
callName();
}
即将父类的baseName赋值为“base”,赋值后调用callName();
6、callName()方法在子类中被重写,因此调用子类的callName(),子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行。
7、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才为子类字段baseName 分配好存储空间,随后为其赋值:
可见,在baseName = "sub"执行前,子类的callName()已经执行,所以子类的baseName为默认值状态null;
二、总结
java对象初始化顺序
1.父类静态初始化方法 static{ }
2.子类静态初始化方法 static{ }
3.父类字段初始化 ,如private String name ="base"
4.父类非静态初始化方法 {}
5.父类构造方法
6.子类字段初始化,如private String name="sub";
7.子类非静态初始化方法{}
8 子类构造方法