看下面的代码:
//父类
public class Token {
static int a;
static {
a = 10;
System.out.println("这是父类的静态代码块" + a);
}
public Token() {
System.out.println("父类构造方法!");
}
}
//子类
public class TokenChrild extends Token {
static int a;
public TokenChrild() {
System.out.println("子类构造方法!");
}
static {
a = 10;
System.out.println("这是子类的静态代码块" + a);
}
}
//测试
public class Main {
public static void main(String[] args) {
TokenChrild t1 = new TokenChrild();
System.out.println();
TokenChrild t2 = new TokenChrild();
}
}
上面代码的输出结果:

很好理解这个点,你实例化一个类时,JVM加载这个类的代码的顺序是:父类静态域(静态成员变量和静态代码块) -> 子类静态域 -> 父类构造方法 -> 子类构造方法,而静态域的生命周期与类同在,且只加载一次。上面这个结果在意料之内。
再看下面这段代码:
//父类
public class Token {
static int a;
static {
a = 10;
System.out.println("这是父类的静态代码块" + a);
}
public Token() {
System.out.println("父类构造方法!");
execute();
}
public void execute() {
System.out.println("父类实例方法!");
}
}
//子类
public class TokenChrild extends Token {
static int a;
int b = 1;
static {
a = 10;
System.out.println("这是子类的静态代码块" + a);
}
public TokenChrild() {
super();
System.out.println("子类构造方法!");
execute();
}
public void execute() {
System.out.println("子类实例方法: " + b);
}
}
//测试类
public class Main {
public static void main(String[] args) {
TokenChrild t1 = new TokenChrild();
}
}
上面代码执行结果:

在父类的构造方法中调用了子类的实例方法,从而父类的构造方法运行时,子类的实例方法也运行了,但是这个时候,子类的构造方法还没有运行,也就是子类的属性还没有加载出来,所以这时候 i 的值为0,后面子类构造方法中调用子类的实例方法,这个时候,子类的属性都已经加载好了,所以 i 的值为1.
本文详细解析了Java中父类和子类的构造方法及静态代码块的执行顺序,阐述了在父类构造方法中调用子类实例方法时,子类属性初始化状态的影响。

被折叠的 条评论
为什么被折叠?



