前言

对Java目标初始化进程 代码块与结构器调用次序进行整理阐明。先说定论详细证明在下文。

代码加载的优先级次序

静态代码块、静态成员变量->非静态代码块、非静态成员变量->new其他目标调用对应目标结构办法(在本地目标的办法外包括结构办法)->new本地目标调用结构办法。

【注意:若new目标时,该目标中有静态代码块和非静态代码块,每new一次目标,非静态代码块都会履行一次,但静态代码块只会履行一次往后new目标都不会再履行。】

结构办法的履行次序

父类静态代码块(静态变量 > 静态块) > 子类的静态代码块 > 父类结构代码块、结构办法> 子类的结构代码块、结构办法

各种代码块的界说

静态代码块

class Demo{ static { //静态代码块...... } }

特色: 1、Java静态代码块中的代码会在类加载JVM时运转,且只被履行一次 2、静态块常用来履行类属性的初始化 ,和一些全局初始化的工作 3、静态块优先于各种代码块以及结构函数,如果一个类中有多个静态代码块,会依照书写次序顺次履行 4、静态代码块能够界说在类的任何地方中除了办法体中【这儿的办法体是任何办法体】 5、静态代码块不能拜访一般变量

有关静态代码块再详细介绍下:

静态代码块:在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会履行一次。

因为JVM在加载类时会履行静态代码块,所以静态代码块先于主办法履行。 如果类中包括多个静态代码块,那么将依照”先界说的代码先履行,后界说的代码后履行”。 【注意:1 静态代码块不能存在于任何办法体内。2 静态代码块不能直接拜访静态实例变量和实例办法,需要经过类的实例目标来拜访。】 实例代码块 实例代码块 又名 结构初始化块 , 结构代码块 , 初始化块 。

class Demo{ { //实例代码块...... } }

特色:

1、结构代码块在创立目标时被调用,每次创立目标都会调用一次
2、结构代码块优先于结构函数履行,同时结构代码块的运转依赖于结构函数
3、结构代码块在类中界说

部分代码块

部分代码块又名 一般代码块 , 办法代码块

class Demo{ public void test(){ { //部分代码块...... } } }

特色: 1、一般代码块界说在办法体中 2、一般代码块与实例代码块的格式一致都是{} 3、一般代码块与结构代码块唯一能直接看出的区别是结构代码块是在类中界说的,而一般代码块是在办法体中界说的 4、能够限定变量生命周期,及早释放,提高内存利用率

验证各代码块的履行次序

举例代码如下:

class Init {
    public Init() {
        System.out.println("无参结构器");
    }
    public Init(int a) {
        System.out.println("有参结构器");
    }
    {
        System.out.println("实例代码块1");
    }
    {
        System.out.println("实例代码块2");
    }
    {
        System.out.println("实例代码块3");
    }
    static {
        System.out.println("静态初始化块1");
    }
    static {
        System.out.println("静态初始化块2");
    }
    public void method(){
    	{
    		System.out.println("一般初始化块");
    	}
    }
}

测试代码 如下:

class Demo {
    public static void main(String[] args) {
        Init init1 = new Init();
        init1.method();
        System.out.println("------------");
        Init init2 = new Init();
        init2.method();
        //多打印几个目标的意图是:方便看出Static静态代码块 是否只履行一次!!!
        System.out.println("------------");
        Init init3 = new Init();
        init3.method();
    }
}

运转成果如下图:

Java对象初始化过程代码块与构造器调用顺序

定论:

履行次序为:静态代码块 > 实例代码块 > 结构函数 > 一般代码块,

且静态代码块,类加载的时候就会调用,且只调用一次(随着类的加载而履行)。

那么类什么时候会被加载呢?

– 创立目标实例时(new)
– 创立子类目标实例,父类也会被加载
– 使用类的静态成员时(静态属性,静态办法)

验证存在承继联系中各代码块的履行次序

举例承继联系为 Three——> Two——> One, 代码如下:

class One {
    public One() {
        System.out.println("One结构器");
    }
    {
        System.out.println("One实例化块");
    }
    static {
        System.out.println("One静态代码块");
    }
}
class Two extends One {
    public Two() {
        System.out.println("Two结构器");
    }
    {
        System.out.println("Two实例化块");
    }
    static {
        System.out.println("Two静态代码块");
    }
}
class Three extends Two {
    public Three() {
        System.out.println("Three结构器");
    }
    {
        System.out.println("Three实例化块");
    }
    static {
        System.out.println("Three静态代码块");
    }
}
//测试代码 如下:
public class Demo {
    public static void main(String[] args) {
        Three three = new Three();
        System.out.println("-----");
        Three three1 = new Three(); //重复履行的意图是为了 验证static是否只履行一次
        System.out.println("-----");
        Two three2 = new Three();   //验证 多态的情况下 用后面的类进行初始化 成果和上面相同
    }
}

Java对象初始化过程代码块与构造器调用顺序

依据履行成果可知,在多个类的承继中存在初始化块、静态初始化块、结构器,履行真实次序为:先后履行父类A的静态块,父类B的静态块,最终子类的静态块,然后再履行父类A的实例代码块和结构器,然后是B类的实例代码块和结构器,最终履行子类C的实例代码块和结构器【注:这儿的ABC对应One、Two、Three 】

定论:

多个类的承继中初始化块、静态初始化块、结构器的履行次序为:

父类静态块——>子类静态块——>父类实例代码块——>父类结构器——>子类实例代码块——>子类结构器 ——>(如果有部分代码块, 再正常履行即可, 这儿就没必要进行测试了)

经过字节码深究实例代码块优先于结构器原因

我们那一段代码作为例子阐明下,代码如下:

class Init {
    public Init() {
        System.out.println("无参结构器");
    }
    public Init(int a) {
        System.out.println("有参结构器");
    }
    {
        System.out.println("实例代码块1");
    }
    {
        System.out.println("实例代码块2");
    }
    {
        System.out.println("实例代码块3");
    }
    static {
        System.out.println("静态初始化块1");
    }
    static {
        System.out.println("静态初始化块2");
    }
    public void method(){
        {
            System.out.println("一般初始化块");
        }
    }
}

接下来让我们看看 , Init.java编译完的的字节码文件(Init.class)

Java对象初始化过程代码块与构造器调用顺序

从这个字节码文件就能够很明晰的看出, 实例代码块实际上是被顺次放到了结构办法的第一句, 所以能够的出此定论: 实例代码块的履行次序是优先于结构器的。