今天学长出了一道题,我发现我竟然对初始化代码块的存在一无所知。
初始化代码块(initialization block)是初始化数据域的第三种机制(前两种分别是构造器和声明时赋值)。只要构造类的对象,只写代码块就会被自动执行,不需要调用。1
2
3
4
5
6
7
8
9
10
11class A
{
//数据域
private int id;
private int name;
//object initilization block
{
id = 4;
name++;
}
}
构造类时,先运行初始化代码块,再运行构造方法的主体。
注:
为了避免循环定义,不要读取初始化以后的域
Java是按照编程顺序来执行实例变量初始化器和实例初始化器中的代码的,并且不允许顺序靠前的实例代码块初始化在其后面定义的实例变量
对静态域进行初始化,可直接提供一个初始化值(private ststic int id = 1;),也可通过静态的初始化块进行初始化。1
2
3static{
}
再类第一次加载时,即进行静态域的初始化。且所有的静态初始化语句与静态初始化块都将按类的定义顺序执行。
注:
JVM加载类时执行(仅执行一次)
- 随类的加载执行,只执行一次,并优先于主函数main。
- 静态代码初始化块是给类初始化,构造代码块是给对象初始化。
- 静态代码块中的变量是局部变量,等同于普通函数中的局部变量。
- 一个类中可以有多个静态代码块。
当涉及到继承时,按照如下顺序执行:
执行父类的静态代码块,初始化父类静态成员变量
执行子类的静态代码块,初始化子类静态成员变量
执行父类的构造代码块,执行父类的构造函数,初始化父类普通成员变量
执行子类的构造代码块,执行子类的构造函数,初始化子类普通成员变量
I.1
2
3
4
5int a;
{
b = a;
}
int b;
II.1
2
3
4
5int b;
{
b = a;
}
int a;
I能够通过编译,但II报错:非法前引用。
静态代码块只能对其之前的数据进行访问,对于其之后的数据可以赋值但不能被访问。
—《深入理解Java虚拟机》
总结:
调用构造器的具体处理步骤:
- 所有数据域被初始化为默认值(0,false,null)
- 按类声明的顺序执行 与初始化语句和初始化
- 若构造器首行调用了第二个构造器,则执行第二个构造器主体
- 执行构造器
一个Java对象的创建过程往往包括类初始化和类实例化两个阶段,类实例化包括实例变量初始化、实例代码块初始化以及构造函数初始化
实际上,如果我们对实例变量直接赋值或者使用实例代码块赋值,那么编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后,构造函数本身的代码之前
实例化对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。
其实一般也很少使用到初始化块,因为都是在构造方法内完成类的初始化。初始化块一般适用于加载类时加载本地库。