只恨上课的时候没有认真听讲,在网易笔试的过程中碰到了Java类初始化顺序的题目。
马上重新学习,不敢怠慢,写下此文
无继承的类的初始化过程
在Java中类的初始化优先级是: 静态 > 实例 > 构造器
静态:包括静态变量,静态初始化块,也就是关键字 static
修饰部分的代码,静态部分的初始化,按照类内的定义顺序执行初始化。
实例:和C++不同,Java的实例变量(instance variable)支持类内初始化,这里的“实例”,指的就是实例变量、或实例初始化块。执行顺序也是按照类内定义的顺序进行初始化
构造器:就是构造方法,这个就不用多说
看下面的实验代码
/**
* @author Lisupy
* @email zhong550413470@gmail.com
* 类初始化测试
* */
public class InitialOrderTest {
// instance variable
private String val = "instance val";
// instance initial block
{
System.out.println(val);
System.out.println("Executing in instance initial block");
}
// static variable
private static String staticVal = "static val";
// static initial block
static {
System.out.println(staticVal);
System.out.println("Executing in static block");
}
// Constructor
public InitialOrderTest(){
System.out.println("Executing in Constructor");
}
public static void main(String[] args){
new InitialOrderTest();
new InitialOrderTest();
}
}
这段代码运行的结果为
static val
Executing in static block
instance val
Executing in instance initial block
Executing in Constructor
instance val
Executing in instance initial block
Executing in Constructor
静态初始化部分在类被加载的时候先执行且执行一次,实例初始化部分在每次创建新的实例对象时先运行,再运行构造方法
上面的代码中,由于静态初始化代码的静态块依赖于静态变量,所以二者的顺序不能替换,替换后会出现编译错误 java: illegal forward reference
, 这也证明了代码的执行顺序是按照类内定义的顺序执行的。
有继承关系的类的初始化过程
对于有继承关系的类的初始化情况,比上面的复杂,所以也经常列为考点。但是再复杂也万变不离其宗, 就是优先级按照 "静态">"实例">"构造器", 但是有稍微一点不同,看下面的代码
/**
* 代码转于http://www.cnblogs.com/jackyrong/archive/2008/08/12/1266161.html
*/
class Parent {
// 静态变量
public static String p_StaticField = "父类--静态变量";
// 变量
public String p_Field = "父类--变量";
// 静态初始化块
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
// 初始化块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
// 构造器
public Parent() {
System.out.println("父类--构造器");
}
}
public class SubClass extends Parent {
// 静态变量
public static String s_StaticField = "子类--静态变量";
// 变量
public String s_Field = "子类--变量";
// 静态初始化块
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
// 初始化块
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
// 构造器
public SubClass() {
System.out.println("子类--构造器");
}
// 程序入口
public static void main(String[] args) {
new SubClass();
}
}
运行结果如下
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
对于这个运行结果,说一说我的见解:
总体来说,初始化过程满足上面所说的优先级 "静态">"实例">"构造器",但是要添加一个另外的条件"父类">"子类"
就上述的代码来说,在类加载的过程中就必须满足 "父类" > "子类",所以父类的静态代码 优先于 子类的静态代码,符合上述运行结果
实例初始化代码是在创建类的过程中运行的,由于子类的初始化可能会依赖到父类的初始化的成员,所以先运行父类的实例初始化块和构造方法,再运行子类的初始化块和构造方法
上述的内容均属于我自己的理解,有可能和实际有所区别,如果各位看官发现任何错误,请指出来,我会听取您的意见改善这篇博文。