写了快两年的Java了,断断续续也看了一些书,但是似乎还是没有很深入理解。今天写代码的时候突然想到一个问题,Java继承的方法是如何初始化的,一时间感觉到很模糊,实在惭愧。趁着今天不加班,网上找了些资料。废话不多说,上代码:
package test;
public class Child extends Father {
int a = prt("Child member variable initialized");
static int b = prt("Child static variable initialized");
Child() {
prt("Child constructor");
}
static int prt(String s) {
System.out.println(s);
return 1;
}
public static void main(String[] args) {
prt("Child main");
Child b = new Child();
}
}
package test;
class Father {
int i = prt("Father member variable initialized");
int j;
static int v= prt("Father static variable initialized");
Father() {
System.out.println("Father construct");
}
static int prt(String s) {
System.out.println(s);
return 1;
}
public static void main(String[] args){
System.out.println("Father main");
Father i = new Father();
}
}
Father类的输出应该问题不大,Child类的输出顺序如下:
Father static variable initialized
Child static variable initialized
Child main
Father member variable initialized
Father construct
Child member variable initialized
Child constructor
总结一下:
1.静态成员变量最先初始化,父类>子类
2.进入main方法
3.初始化父类成员变量
4.调用父类构造器
5.初始化子类成员变量
6.调用子类构造器
另外需要注意,如果有多态的情况,父类构造器动态调用实现类的方法,此时子类的成员变量还没有初始化,都为类装载后的初始值。
其实这些知识点在上次看的一本书里面都看过,只是过了一段时间又一干二净了。类的加载,编译,初始化这些还是很重要的,要经常温习,重点还是要深入体会。
类加载的顺序为,先装载类对象,也就是Child.class,此时装载器发现有父类,先去装载Father.Class,之后初始化Father静态成员变量,再初始化Child.Class静态成员变量。此时普通成员变量还没有初始化。接下来执行main方法,此时需要调用子类构造器,这会触发父类构造器调用。在调用父类构造器之前需要初始化父类的成员变量。接下来就是初始化子类成员变量,最后调用子类构造器。
几年没写博客了,先把golang过一遍,再回到Java上来。就这么多吧。