Java - [面向对象]初始化代码块

2020/03/01

实例初始化代码块

首先来看个有意思的问题:实例初始化代码块初始化实例成员变量构造器初始化三者的执行顺序如何?

@Getter
public class InstanceInit {

    public InstanceInit(){
        this.age = 40;
    }

    {
        age = 10;
    }

    int age = 20;

    {
        age = 30;
    }
}

@Test
void instanceInitTest(){
    InstanceInit ii = new InstanceInit();
    System.out.println("Age is " + ii.getAge());
}

老规矩,age是多少?

答案是40

原因是:先执行实例初始化代码块实例成员变量初始化,再执行构造器初始化

而前两者是根据具体的代码顺序决定的。

如下图所示:

再来说下,继承关系下实例初始化代码块构造器的执行顺序:

创建一个Java对象时,不仅会执行该类的实例初始化代码块构造器,而且会一直追溯到java.lang.Object类,优先执行Object类的实例初始化代码块构造器,然后顺着父类关系一层层执行,最后才是该类。

举个例子:

public class BaseClass {

    public BaseClass(){
        System.out.println("Constructor in BaseClass.");
    }

    {
        System.out.println("Instance init block in BaseClass.");
    }
}

public class SubClass extends BaseClass{

    public SubClass(){
        System.out.println("Constructor in SubClass.");
    }

    {
        System.out.println("Instance init block in SubClass.");
    }
}

@Test
void instanceInitSeqTest(){
    new SubClass();
}

// Instance init block in BaseClass.
// Constructor in BaseClass.
// Instance init block in SubClass.
// Constructor in SubClass.

其实还执行了Object类中的默认构造函数,只不过它没有打印出任何信息~

类初始化代码块

先来看下类初始化代码块初始化类成员变量之间的顺序关系:

public class StaticInit {

    static {
        a = 5;
    }

    public static int a = 10;

    static {
        a = 20;
    }
}

@Test
void staticInitTest(){
    System.out.println("a = " + StaticInit.a); // 20
}

实验证明,和实例执行顺序一致。

再来看下继承关系下,类初始化代码块实例初始化代码块构造器之间的执行顺序:

public class Root {
    static {
        System.out.println("Root static init block.");
    }

    {
        System.out.println("Root init block.");
    }

    public Root(){
        System.out.println("Root constructor.");
    }
}

public class Mid extends Root{

    static {
        System.out.println("Mid  static init block.");
    }

    {
        System.out.println("Mid  init block.");
    }

    public Mid(){
        System.out.println("Mid  constructor.");
    }

    public Mid(String name){
        this();
        System.out.println(name + " in Mid constructor.");
    }
}

public class Leaf extends Mid{

    static {
        System.out.println("Leaf static init block.");
    }

    {
        System.out.println("Leaf init block.");
    }

    public Leaf(){
        super("frankie");
        System.out.println("Leaf constructor.");
    }
}

@Test
void staticInitBlockTest(){
    new Leaf();
    System.out.println("----------------");
    new Leaf();
}

有意思的是第二次创建Leaf对象。

由于Leaf类已经初始化成功,所以第二次创建该对象时,无需执行对应的类初始化代码块

结果如下:

Reference

  • 《疯狂Java讲义》 - 5.9 初始化块


一位喜欢提问、尝试的程序员

(转载本站文章请注明作者和出处 姚屹晨-yaoyichen

Post Directory