1、代码块的分类

代码块是在程序之中使用”{}“定义起来的一段程序,根据代码块声明位置以及声明关键字的不同可以分为四种:普通代码块、构造代码块、静态代码块、同步代码块

代码块的执行顺序:静态代码块→构造代码块→构造函数→普通代码块

继承关系中的执行顺序:父类静态块→子类静态块→父类代码块→父类构造器→子类代码块→子类构造器

2、代码块详解
2.1 普通代码块

1、普通代码块是定义在方法体中
2、可以解决在一个方法中过长导致出现重复变量定义的问题。

public class Demo{
	public static void main(String[] args){
		{
			int x = 10;
			System.out.println("x =" + x);
		}
		int x = 10;
		System.out.println("x = " + x);
	}
}

在上面这个例子中使用"{}"普通代码块定义了一个变量 ”x”,这样就可以与外部的x互不影响了。

2.2 构造代码块

1、在一个类中定义
2、使用new关键字实例化对象时进行调用,且每创建一个都会调用一次
3、构造代码块先于构造函数执行,同时构造代码块的运行依赖于构造函数
4、适用于统计类的实例化对象数量

自定义Person类

public class Person{
	public Person{
		System.out.println("【构造方法】Person类构造方法执行");
	}
	{
		System.out.println("【构造块】Person类中构造块执行");
	}
}

测试类:

public class Demo{
	public static void main(String[] args){
		Person per1 = new Person();
		Person per2 = new Person();
	}
}

运行结果:

【构造块】Person类中构造块执行
【构造方法】Person类构造方法执行
【构造块】Person类中构造块执行
【构造方法】Person类构造方法执行

构造代码块与普通代码块的格式一样:都是将代码用{}围起来,区别就在于定义的地方不一致。

2.3静态代码块

1)Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次,也就是说这些代码不需要实例化类就能够被调。

2)一般情况下,如果有些代码必须在项目启动的时候就执行的时候,就需要使用静态代码块,所以静态块常用来执行类属性的初始化!

代码示例:

class Message{
	public static String getCountry(){
		return "China";
	}
}
class Person{
	private static String country;
	static{		//静态代码块
		country = Message.getCountry();
		System.out.println(country);
	}
}
public class Demo{
	public static void main(String[] args){
		new Person();
	}
}

本程序在Person类中设置了静态代码块,在类第一次使用时进行初始化,之后再新建Person 其Country属性均属于”China“

3)关于Static静态代码块的五个小结点

1、Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次
2、静态代码块常用于执行类属性的初始化
3、静态块优先于各种代码块以及构造函数,如果一个类中有多个静态代码块,会按照书写顺序依次执行
4、静态代码块可以定义在类的任何地方中除了方法体中【这里的方法体是任何方法体】
5、静态代码块不能访问普通变量

  • 针对第四点: 由于普通方法是通过加载类,然后new出实例化对象,通过对象才能运行这个方法,而静态代码块只需要加载类之后就能运行了。
    对于静态方法,在类加载的时候,静态方法也已经加载了,但是我们必须要通过类名或者对象名才能访问,也就是说相比于静态代码块,静态代码块是自己主动运行的,而静态方法是被动调用运行的。
    不管是哪种方法,我们需要明确静态代码块的存在,在类加载的时候就自动运行了,而放在不管是普通方法还是静态方法中,都是不能自动运行的。
  • 针对第五点:static定义的代码块,可以在没有实例化对象的时候使用。普通变量只能被实例化对象使用,所以如果没有对象存在,那么static无法调用普通变量。

4)Static静态代码块使用格式

static{
	...
}
3、执行顺序的测试
3.1 同一个类
package com.gx.initializationblock;

public class Initializationblock {

    int intA;
    int intB;


    public Initializationblock() {
        System.out.println("无参构造器00000000");
    }

    public Initializationblock(int a) {
        System.out.println("一个参数的构造器");
        
    }

	// 构造块
    {
        intA = 10;
        intB = 15;

        System.out.println("构造代码块11111");
    }

    {
        System.out.println("构造代码块22222");
    }

    {
    	
        System.out.println("构造代码块33333");
    }

    //静态初始化块
    static {
        System.out.println("静态代码块01010101");
    }

    static {
        System.out.println("静态代码块0202020202");
    }
    
    //普通构造块
    public void method(){
    	{
    		System.out.println("普通代码块");
    	}
    }
}

测试demo

package com.gx.initializationblock;

/* 初始化块一
	 * 因为静态块是在类的初始化阶段完成的,
	 * 因此在创建某个类的第二个对象时,该类的静态块就不会执行了
	 * 
	 * 在单个类中,静态代码块,构造代码块,构造器 普通代码块
 */
public class Demo1 {
    public static void main(String[] args) {
        Initializationblock initializationblock = new Initializationblock();
        initializationblock.method();
        System.out.println("------------");
        //多打印几个对象的目的是:好看出Static静态代码块只执行一次!!!
        Initializationblock initializationblock2 = new Initializationblock(); 
        initializationblock2.method();
        
        Initializationblock initializationblock3 = new Initializationblock();
        initializationblock3.method();
    }
}

运行结果:

静态代码块01010101
静态代码块0202020202
构造代码块11111
构造代码22222
构造代码块33333
无参构造器00000000
普通代码块
------------
构造代码块11111
构造代码块22222
构造代码块33333
无参构造器00000000
普通代码块
构造代码块11111
构造代码块22222
构造代码块33333
无参构造器00000000
普通代码块

得出结论:执行顺序静态代码块 > 构造代码块 > 构造函数 > 普通代码块

3.2继承类中

继承关系为 BaseThree——> BaseTwo——> BaseOne

BaseOne

package com.gx.initializationblock;

public class BaseOne {

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

    {
        System.out.println("BaseOne初始化块");
       
    }

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

}

BaseTwo

package com.gx.initializationblock;

public class BaseTwo extends BaseOne {
    public BaseTwo() {
        System.out.println("BaseTwo构造器");
    }

    {
        System.out.println("BaseTwo初始化块");
    }

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

BaseThree

package com.gx.initializationblock;

public class BaseThree extends BaseTwo {
    public BaseThree() {
        System.out.println("BaseThree构造器");
    }

    {
        System.out.println("BaseThree初始化块");
    }

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

测试demo2类

public class Demo2 {
    public static void main(String[] args) {
        BaseThree baseThree = new BaseThree();
        System.out.println("-----");
        BaseThree baseThree2 = new BaseThree();

    }
}

运行结果

BaseOne静态初始化块

BaseTwo静态初始化块
BaseThree静态初始化块
BaseOne初始化块
BaseOne构造器
BaseTwo初始化块
BaseTwo构造器
BaseThree初始化块
BaseThree构造器
-----

BaseOne初始化块
BaseOne构造器
BaseTwo初始化块
BaseTwo构造器
BaseThree初始化块
BaseThree构造器

多个类的继承中构造代码块、静态代码块、构造器的执行顺序为:先后执行父类A的静态块,父类B的静态块,最后子类的静态块,然后再执行父类A的构造代码块和构造器,然后是B类的构造代码块和构造器,最后执行子类的构造代码块和构造器【注:这里的ABC对应BaseOne、BaseTwo、BaseThree 】

结论:多个类的继承中构造代码块、静态代码块、构造器的执行顺序为:父类静态块——>子类静态块——>父类代码块——>父类构造器——>子类代码块——>子类构造器