初始化块
1. 初始化块定义
初始化块是Java类里可出现的第4种成员(成员变量、方法、构造器、初始化块),一个类里可以有多个初始化块,相同类型的初始化块之间有顺序,按照定义的先后顺序执行。
定义语法:
[static] {
// 初始化块的可执行性代码
…
}
初始化块的修饰符要么是static
要么没有,分别称为:
- 静态/类初始化块:有
static
修饰; - 非静态/普通初始化块:无
static
修饰。
初始化块虽然也是Java类的一种成员,但它没有名字(标识),因而无法通过类、对象来调用初始化块。
2. 非静态初始化块
非静态初始化块,简称初始化块,只在创建Java对象时隐式执行,而且在执行构造器代码之前执行。
虽然Java允许一个类里定义多个非静态初始化块,但这意义不大,因为初始化块是在创建Java对象时隐式执行的,而且它们总是(按代码中的顺序)全部执行,因此完全可以把多个普通初始化块合并成一个初始化块,让程序更加简洁。
与构造方法类似,创建Java对象时不仅会执行该类的普通初始化块和构造器,而且系统会一直上溯直到java.lang.Ojbect
类。
就具有构造器性质的三种成分而言——声明字段时的默认值初始化语句、初始化块、构造器,其在调用构造器时的执行顺序是:
- 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器;
- 否则:
- 所有数据字段分配内存并初始化为其默认值(
0, false, null
) - 按照在类声明中出现的顺序,依次执行所有的字段默认值初始化语句、初始化块。
- 所有数据字段分配内存并初始化为其默认值(
- 执行构造器的主体代码。
由上可知,实际上初始化块和声明字段时的默认值初始化语句是一种假象。当用javac
命令编译Java类后,相应的语句实际上会被“还原”到每个构造器中,且位于构造器所有代码的前面:

Person.java
@Data public class Person { { System.out.println("-----进入上面的初始化块-----"); System.out.println(this); this.sex = true; this.age = 4; this.aChar = 'b'; this.bigDecimal = BigDecimal.ONE; this.user = new User("111", "111", "111"); System.out.println(this); } private boolean sex = false; private int age = 3; private char aChar = 'a'; private BigDecimal bigDecimal = BigDecimal.ZERO; private User user = new User("000", "000", "000"); { System.out.println("-----进入下面的初始化块-----"); System.out.println(this); this.sex = true; this.age = 5; this.aChar = 'c'; this.bigDecimal = BigDecimal.TEN; this.user = new User("222", "222", "222"); System.out.println(this); } public Person() { System.out.println("-----我是构造器主体代码-----"); } public static void main(String[] args) { new Person(); } }
Person.class
public class Person { private boolean sex; private int age; private char aChar; private BigDecimal bigDecimal; private User user; public Person() { System.out.println("-----进入上面的初始化块-----"); System.out.println(this); this.sex = true; this.age = 4; this.aChar = 'b'; this.bigDecimal = BigDecimal.ONE; this.user = new User("111", "111", "111"); System.out.println(this); this.sex = false; this.age = 3; this.aChar = 'a'; this.bigDecimal = BigDecimal.ZERO; this.user = new User("000", "000", "000"); System.out.println("-----进入下面的初始化块-----"); System.out.println(this); this.sex = true; this.age = 5; this.aChar = 'c'; this.bigDecimal = BigDecimal.TEN; this.user = new User("222", "222", "222"); System.out.println(this); System.out.println("-----我是构造器主体代码-----"); } public static void main(String[] args) { new Person(); } }
main方法输出:
-----进入上面的初始化块----- Person(sex=false, age=0, aChar= , bigDecimal=null, user=null) Person(sex=true, age=4, aChar=b, bigDecimal=1, user=User(id=111, name=111, email=111)) -----进入下面的初始化块----- Person(sex=false, age=3, aChar=a, bigDecimal=0, user=User(id=000, name=000, email=000)) Person(sex=true, age=5, aChar=c, bigDecimal=10, user=User(id=222, name=222, email=222)) -----我是构造器主体代码-----
3. 静态初始化块
普通初始化块负责对对象进行初始化,类初始化块负责对类进行初始化。
static
初始化块属于类的静态成员,是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行,故而静态初始化块总是比普通初始化块先执行。
static
初始化块成功执行一次后,意味着该类初始化完成,后边再次创建该类实例时便不会再调用static
初始化块。
static
初始化块同样是上溯到java.lang.Object
类,先执行顶层、再执行当前类的static
初始化块。
类似非静态初始化块,static
初始化块和声明静态成员变量时所指定的初始值都是该类的初始化代码,它们的执行顺序与源程序中的排列顺序相同。
当JVM第一次主动使用一个类时,系统会在准备阶段为该类的所有静态成员变量分配内存;在初始化阶段则负责初始化这些静态成员变量。