三者的执行顺序为静态代码块-->构造代码块-->构造方法,而且静态代码块只会执行一次。
比如创建一个Parent类:
public class Parent{
{
System.out.println("我是parent的构造代码块");
}
static{
System.out.println("我是parent的静态代码块");
}
public Parent(){
System.out.println("我是parent构造方法中的代码块");
}
}
再创建一个Son类继承Parent类:
public class Son extends Parent{
{
System.out.println("我是son的构造代码块");
}
static{
System.out.println("我是son的静态代码块");
}
public Son(){
System.out.println("我是son构造方法中的代码块");
}
}
创建一个测试类Test:
public class Test {
public static void main(String[] args) throws InterruptedException {
while(true){
new Son();
Thread.sleep(5000);
}
}
}
输出结果:
我是parent的静态代码块 1
我是son的静态代码块 2
我是parent的构造代码块 3
我是parent构造方法中的代码块 4
我是son的构造代码块 5
我是son构造方法中的代码块 6
我是parent的构造代码块 7
我是parent构造方法中的代码块 8
我是son的构造代码块 9
我是son构造方法中的代码块 10
1-6行是第一次执行时打印出来的结果,7-10行是执行第一次循环打印的结果,后续的打印结果会重复7-10行;
由结果1-2行可以,静态代码块是在类进行加载的时候执行的,且如果一个类有父类时jvm会先加载父类,再去加载子类;
由3-4行得出结论:构造代码块实在构造方法之前执行的,其作用可以用于在 创建对象之前对属性进行初始化;由3-6得出结论当创建一个子类时,jvm会首先执行父类的构造代码块和构造方法(具体有没有创建父类的对象,网上各执己见大家可以搜搜看,这里不便多说);
由1-10行以及后续打印出的结果,可以得出结论:静态代码块只会执行一次(可以理解为被静态代码块包含的代码属于类的,不属于任何一个对象,因此再执行时只会执行一次);
备注:
注意Test类中的main方法中使用了while(true)循环的打印,此时是同一个jvm实例在循环创建对象,由于第一次加载Son类和Parent类时执行了静态代码块,所以第二次创建对象时就不会再执行静态代码块。因为运行Java应用程序时会创建一个jvm实例(即每一个Java应用程序在window进程窗口中都是一个javaw.exe进程),该jvm会进行类的加载,因此如果多次将程序执行为Java Application,每次得到的结果都是1-6行(运行应用程序时创建一个jvm实例,此时jvm中尚未加载任何类,jvm会去重新加载Sonh和Parent类);