首先先放上我们写的一个.Java文件的前世今生。
现在上代码,查看static,main,构造方法的执行顺序
public class ClassA {
// 定义静态变量
public static ClassA classa = new ClassA();
static {
System.out.println("ClassA的静态代码块");
}
public ClassA() {
System.out.println("ClassA的构造方法");
}
//构造代码块
{
System.out.println("ClassA的构造代码块");
}
}
public class ClassB extends ClassA {
static {
System.out.println("ClassB的静态代码块");
}
public ClassB() {
System.out.println("ClassB的构造方法");
}
{
System.out.println("ClassB的构造代码块");
}
public static ClassC classc = new ClassC();
public void excute() {
System.out.println("执行方法");
}
}
public class ClassC {
public ClassC() {
System.out.println("ClassC的构造方法");
}
}
测试类
public class Test {
static {
System.out.println("Test的静态代码块");
}
public static void main(String[] args) {
System.out.println("执行main方法");
ClassB b = new ClassB();
b.excute();
}
}
输出的结果为
-
-
-
1 Test的静态代码块
2 执行main方法
3 ClassA的构造代码块
4 ClassA的构造方法
5 ClassA的静态代码块
6 ClassB的静态代码块
7 ClassC的构造方法
8 ClassA的构造代码块
9 ClassA的构造方法
10 ClassB的构造代码块
11 ClassB的构造方法
12 执行方法
结合上图这里解释下原因
一.首先main方法是一个程序的入口,所以它所在的类优先加载也优先执行,在执行完类的全部加载过程(加载、验证、准备、解析、初始化)后main方法才会进行执行
二.static关键字修饰的变量或者代码块,是在准备阶段加载的,多个同级别static变量或者代码块是按照定义的前后顺序执行的
三.当创建一个子类对象的时候(调用构造方法)首先会调用父类的构造方法
四.构造代码块是依赖于构造方法存在的,会在每个构造方法中都添加上构造代码块的代码(下面多说明)
详细说明下:
main方法是程序的入库,所以所在类Test优先加载和执行,当Test类进行类加载的准备阶段就执行了Test类的静态代码块,等Test类完成初始化后才执行main方法。(解释前两个输出)
接下来是要去ClassB的实例,ClassB继承了ClassA所以这里先操作ClassA类,也就是ClassA进行加载,里面有静态变量和静态代码块,根据上面说的第二点,知道先执行 public static ClassA classa = new ClassA();调用A类的构造方法创建A实例,因为存在构造代码块,构造方法在执行前一定会先执行了构造代码块的代码。(解释3和4的输出)
创建完A实例,继续按顺序执行静态代码(解释5)
父类文件加载完开始进行子类文件重复上面的原因(解释6、7)
至此类都加载完了执行B的构造方法,根据第四点知道要先执行A类的构造方法(解释8、9、10、11)
再详细说一下第四点,为什么说构造代码块是依赖于构造方法存在的,可以理解为构造代码块不会单独执行,一定要和构造方法一起执行。这里对ClassA的字节码文件进行反编译ClassA.class结果为
public class ClassA
{
public static ClassA classa = new ClassA();
static { System.out.println("ClassA的静态代码块");
}
public ClassA()
{
System.out.println("ClassA的构造代码块");
System.out.println("ClassA的构造方法");
}
}
构造代码块不存在了,直接变成了在构造方法里面,并且放在构造方法原代码的前面。
这里是一个构造方法,如果有多个构造方法呢?这里在添加一个有参的构造方法,内容为直接输入参数,直接贴反编译后的结果
public class ClassA
{
public static ClassA classa = new ClassA();
static { System.out.println("ClassA的静态代码块");
}
public ClassA()
{
System.out.println("ClassA的构造代码块");
System.out.println("ClassA的构造方法");
}
public ClassA(String str)
{
System.out.println("ClassA的构造代码块");
System.out.println(str);
}
}
从结果上可以看出,有多个构造方法是,每个构造方法里的最前面都会填充上构造代码块的代码。