0.基本概念java
类变量是指java类中的static数据成员,实例变量则是指java类中的非static数据成员。因为类变量不须要建立一个对象便可访问,而实例变量则必须与一个具体的对象对应,所以类变量和实例变量的初始化时机是不一样的。本文主要关注如下3个问题:函数
(1)何时初始化类变量?何时初始化实例变量?spa
(2)何时会同时初始化类变量和实例变量?code
(3)在(1)、(2)情形下各个类变量和实例变量的初始化顺序?对象
1.类变量初始化blog
1.1 类变量初始化方式继承
static变量初始化的方式有两种:定义时初始化和static代码块中初始化。以下代码所示:ci
1 class A(){ 2 public static int i = 1;//static变量初始化方式一:在定义时初始化 3 static{//static变量初始化方式二:在static代码块初始化static变量 4 System.out.println("statci 代码块"); 5 } 6 }
1.2 类变量初始化时机编译
根据有无被final关键字修饰,类变量的初始化时机不一样。被final关键字修饰的类变量在编译时就已经被初始化被放置在常量池中了,而没有被final修饰的类变量则在该类首次使用时被初始化。特别须要注意的是,类变量只在该类首次使用时被初始化,这意味着类变量只会被初始化一次。class
在下列情形下,若是一个java类中没有被final修饰的类变量还没有初始化,那么这些没有被final修饰的类变量将会被初始化:
(1)访问该类中没有被final修饰的类变量时;
(2)设置该类中没有被final修饰的类变量时;
(3)调用该类的static方法。
1.2 类变量初始化顺序
类变量初始化会遵循如下三个原则:
(1)在上述3个情形下,首先会初始化该类中全部没有被final修饰的类变量,而后再执行对应的操做;
(2)按照代码中的顺序依次执行static变量定义语句和static代码块;
(3)若是该类有父类且父类的类变量没有初始化,则先初始化父类的类变量;
(4)若是父类还有父类的话,根据(3)的规则,以此类推。
根据上述原则,能够肯定类变量初始化顺序以下:
//没有继承的情形 static变量初始化和static代码块 //有继承的情形 1.父类的static变量初始化和static代码块 2.子类的static变量初始化和static代码块 /*备注: 类变量初始化只有一次,若是某个java类的类变量已经被初始化过了,则上述过程当中的类变量初始化将再也不执行 */
2.实例变量初始化
2.1 实例变量初始化方式
与类变量初始化方式相似,实例变量初始化方式也有两种:定义时初始化和代码块初始化。示例以下:
1 class A(){ 2 public static int i = 1;//实例变量初始化方式一:在定义时初始化 3 4 {//实例变量初始化方式二:在代码块初始化实例变量 5 System.out.println("代码块"); 6 } 7 }
2.2 实例变量初始化时机和顺序
实例变量初始化是在建立该类的对象时进行的,初始化时遵循的原则是:
(1)按照代码中的顺序依次执行实例变量定义语句和实例变量代码块;
(2)若是建立该类的对象时该类的类变量还没有初始化,则先初始化类变量,再初始化实例变量;
(3)若是该类有父类的话,则先建立一个父类对象;而且,若是父类类变量没被初始化时,先初始化父类的类变量,再初始化父类的实例变量,再调用父类的默认构造器;
(4)若是父类还有父类的话,根据(3)的规则以此类推,一直到根基类。
根据上述原则易知,实例变量初始化以前可能会先初始化类变量(这是特别须要留意的一点)。初始化顺序以下:
//没有继承的情形(且该类的类变量未被初始化) 1.static变量初始化和static代码块 2.实例变量初始化和实例变量初始化代码块 3.构造函数 //有继承的情形(且该类和父类的类变量未被初始化) 1.父类的static变量初始化和static代码块 2.子类的static变量初始化和static代码块 3.父类的实例变量初始化和实例变量初始化代码块 4.父类的构造函数 5.子类的实例变量初始化和实例变量初始化代码块 6.子类构造函数 /*备注: 类变量初始化只有一次,若是某个java类的类变量已经被初始化过了,则上述过程当中的类变量初始化将再也不执行 */
3.小结
你们看完若是还不太明白类变量和实例变量的初始化时机和顺序,能够亲自去写一个demo试试,实践才能出真知嘛!
在这里,只强调两点:
(1)类变量只会初始化一次;
(2)类变量和实例变量的初始化时机是不一样的,类变量初始化在首次使用该类的时候进行,实例变量的初始化在建立该类的每一个对象时都会进行。