0.基本概念
类变量是指java类中的static数据成员,实例变量则是指java类中的非static数据成员。由于类变量不需要创建一个对象即可访问,而实例变量则必须与一个具体的对象对应,因此类变量和实例变量的初始化时机是不同的。本文主要关注以下3个问题:
(1)什么时候初始化类变量?什么时候初始化实例变量?
(2)什么时候会同时初始化类变量和实例变量?
(3)在(1)、(2)情形下各个类变量和实例变量的初始化顺序?
1.类变量初始化
根据有无被final关键字修饰,类变量的初始化时机不同。被final关键字修饰的类变量在编译时就已经被初始化被放置在常量池中了,而没有被final修饰的类变量则在该类首次使用时被初始化。特别需要注意的是,类变量只在该类首次使用时被初始化,这意味着类变量只会被初始化一次。
在下列情形下,如果一个java类中没有被final修饰的类变量尚未初始化,那么这些没有被final修饰的类变量将会被初始化:
(1)访问该类中没有被final修饰的类变量时;
(2)设置该类中没有被final修饰的类变量时;
(3)调用该类的static方法。
初始化顺序确定规则:
(1)在上述3个情形下,首先会初始化该类中所有没有被final修饰的类变量,然后再执行对应的操作;
(2)static变量初始化的方式有两种:定义时初始化和static代码块中初始化。因此,在类变量初始化时机时(上述的3种情形)java虚拟机会按照代码中的顺序依次执行static变量定义语句和static代码块。(两种初始化方式的示例代码如下)
(3)如果该类有父类且父类的类变量没有初始化,则先初始化父类的类变量。
1 class A(){ 2 public static final String STR = "hello";//final static变量,在编译时被初始化 3 public static int i = 1;//static变量初始化方式一:在定义时初始化 4 static{//static变量初始化方式二:在static代码块初始化static变量 5 System.out.println("statci 代码块"); 6 } 7 }
根据上述的初始化顺序确定规则,可以确定初始化顺序如下:
//没有继承的情形 static变量初始化和static代码块 //有继承的情形 1.父类的static变量初始化和static代码块 2.子类的static变量初始化和static代码块
2.实例变量初始化
实例变量初始化是在创建该类的对象时进行的,确定初始化顺序的规则下:
(1)如果创建该类的对象时该类的类变量尚未初始化,则先初始化类变量,载初始化实例变量;
(2)如果该类有父类的话,则先创建一个父类对象;并且,如果父类类变量没被初始化时,先初始化父类的类变量,再初始化父类的实例变量,再调用父类的默认构造器;
(3)如果父类还有父类的话,根据(2)的规则以此类推,一直到根基类。
根据上述初始化顺序规则,可以确定的初始化顺序如下:
//没有继承的情形 1.static变量初始化和static代码块 2.实例变量初始化和实例变量初始化代码块 3.构造函数 //有继承的情形 有继承的情形: 1.父类的static变量初始化和static代码块 2.子类的static变量初始化和static代码块 3.父类的实例变量初始化和实例变量初始化代码块 4.父类的构造函数 5.子类的实例变量初始化和实例变量初始化代码块 6.子类构造函数
3.实例