static静态代码块,实例代码块,构造器,普通代码块 各代码块的执行顺序? 及为什么实例代码块优先于构造器? 一篇搞懂!!!

  • Post author:
  • Post category:其他


前言

此博客仅用来粗浅的理解, 各个代码块分别是什么, 并且举例说明他们之间的执行顺序



目录


前言


各个代码块的定义


静态代码块


实例代码块


局部代码块


验证 各代码块的执行顺序


验证 继承关系中 各代码块的执行顺序


为什么实例代码块优先于构造器?


各个代码块的定义


  • 静态代码块

class Demo{    

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

}

特点:

1、Java静态代码块中的代码会在

类加载JVM时运行,且只被执行一次


2、静态块常用来执行类属性的初始化 ,和一些全局初始化的工作

3、静态块优先于各种代码块以及构造函数,如果一个类中有多个静态代码块,会按照书写顺序依次执行

4、静态代码块可以定义在类的任何地方中除了方法体中【这里的方法体是任何方法体】

5、

静态代码块不能访问普通变量


  • 实例代码块

又叫 构造初始化块 , 构造代码块 , 初始化块

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();
    }
}

运行结果:

静态初始化块1
静态初始化块2
实例代码块1
实例代码块2
实例代码块3
无参构造器
普通初始化块
------------
实例代码块1
实例代码块2
实例代码块3
无参构造器
普通初始化块
------------
实例代码块1
实例代码块2
实例代码块3
无参构造器
普通初始化块



结论:



执行顺序




静态代码块 > 实例代码块 > 构造函数 > 普通代码块


验证 继承关系中 各代码块的执行顺序

继承关系为

Three——> Two——> One

, 代码如下:


One类

class One {

    public One() {
        System.out.println("One构造器");
    }

    {
        System.out.println("One实例化块");
    }

    static {
        System.out.println("One静态代码块");

    }

}


Two类

class Two extends One {

    public Two() {
        System.out.println("Two构造器");
    }

    {
        System.out.println("Two实例化块");
    }

    static {
        System.out.println("Two静态代码块");
    }

}


Three类

class Three extends Two {

    public Three() {
        System.out.println("Three构造器");
    }

    {
        System.out.println("Three实例化块");
    }

    static {
        System.out.println("Three静态代码块");
    }

}

测试代码 如下:

public class Demo6 {
    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();   //验证 多态的情况下 用后面的类进行初始化 结果和上面一样

    }
}

运行结果:

One静态代码块
Two静态代码块
Three静态代码块
One实例化块
One构造器
Two实例化块
Two构造器
Three实例化块
Three构造器
-----
One实例化块
One构造器
Two实例化块
Two构造器
Three实例化块
Three构造器
-----
One实例化块
One构造器
Two实例化块
Two构造器
Three实例化块
Three构造器

多个类的继承中初始化块、静态初始化块、构造器的执行顺序为:先后执行父类A的静态块,父类B的静态块,最后子类的静态块,然后再执行父类A的实例代码块和构造器,然后是B类的实例代码和构造器,最后执行子类的实例代码和构造器【注:这里的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("普通初始化块");
    	}
    }
}


接下来让我们看看 , 它的字节码文件(.class)

class Init {
    public Init() {
        System.out.println("实例代码块1");
        System.out.println("实例代码块2");
        System.out.println("实例代码块3");
        System.out.println("无参构造器");
    }

    public Init(int a) {
        System.out.println("实例代码块1");
        System.out.println("实例代码块2");
        System.out.println("实例代码块3");
        System.out.println("有参构造器");
    }

    public void method() {
        System.out.println("普通初始化块");
    }

    static {
        System.out.println("静态初始化块1");
        System.out.println("静态初始化块2");
    }
}

从这个字节码文件就可以很清晰的看出, 实例代码块实际上是被依次放到了构造方法的第一句, 所以可以的出此结论:

实例代码块的执行顺序是优先于构造器的

此文是基于某大佬的博客, 进行了一些细微的补充

转载:

Static静态代码块以及各代码块之间的执行顺序_宜春的博客-CSDN博客_static静态代码块