java中类的成员类型按照属于类还是属于对象来分可分为静态成员和非静态成员,按照数据类型来分可分为基本类型和引用类型,因此可细分为4种.
看如下代码
public class Super { private static int static_int = init_static_basic(); private static String static_str = init_static_refer(); private int a = init_basic(); private String str = init_refer(); static { System.out.println("父类静态初始化之前基本类型变量:"+static_int); System.out.println("父类静态初始化之前引用类型变量:"+static_str); static_int = 1; static_str = "static haha"; } { System.out.println("父类初始化之前基本类型变量:"+a); System.out.println("父类初始化之前引用类型变量:"+str); a = 3; str = "haha"; } private static int init_static_basic(){ System.out.println("在父类静态变量定义处直接赋值之前的基本类型变量:" + static_int); return 10; } private static String init_static_refer(){ System.out.println("在父类静态变量定义处直接赋值之前的引用类型变量:" + static_str); return "static super haha"; } private int init_basic(){ System.out.println("在父类非静态变量定义处直接赋值之前的基本类型变量:" + a); return 5; } private String init_refer(){ System.out.println("在父类非静态变量定义处直接赋值之前的引用类型变量:" + str); return "super haha"; } public Super(){ } public Super(int a, String str) { System.out.println("父类构造函数初始化之前基本类型变量:"+this.a); System.out.println("父类构造函数初始化之前引用类型变量:"+this.str); this.a = a; this.str = str; } }
public class Sub extends Super{ private static int static_sub_int = init_static_basic(); private static String static_sub_str = init_static_refer(); private int sub_a = init_basic(); private String sub_str = init_refer(); static { System.out.println("子类静态初始化之前基本类型变量:"+static_sub_int); System.out.println("子类静态初始化之前引用类型变量:"+static_sub_str); static_sub_int = 1; static_sub_str = "static haha"; } { System.out.println("子类初始化之前基本类型变量:"+sub_a); System.out.println("子类初始化之前引用类型变量:"+sub_str); sub_a =4; sub_str = "haha"; } private static int init_static_basic(){ System.out.println("在子类静态变量定义处直接赋值之前的基本类型变量:" + static_sub_int); return 10; } private static String init_static_refer(){ System.out.println("在子类静态变量定义处直接赋值之前的引用类型变量:" + static_sub_str); return "static sub haha"; } private int init_basic(){ System.out.println("在子类非静态变量定义处直接赋值之前的基本类型变量:" + sub_a); return 5; } private String init_refer(){ System.out.println("在子类非静态变量定义处直接赋值之前的引用类型变量:" + sub_str); return "sub haha"; } public Sub(){ super(); } public Sub(int sub_a, String sub_str) { super(sub_a,sub_str); System.out.println("子类构造器初始化之前基本类型变量:"+this.sub_a); System.out.println("子类构造器初始化之前引用类型变量:"+this.sub_str); this.sub_a = sub_a; this.sub_str = sub_str; } public static void main(String[] args){ new Sub(100,"aas"); } }
首先明确两点
1、父类初始化一定在子类之前
2、静态变量初始化一定在非静态变量之前
而且2的优先级高于1
所以总的顺序为:
1、父类静态成员初始化
2、子类静态成员初始化
3、父类非静态成员初始化
4、子类非静态成员初始化
其次,成员变量初始化有如下几种
1、JVM默认初始化
2、在定义变量处初始化
3、在代码块中初始化
4、在构造函数中初始化(非静态变量)
顺序从上到下(对于非静态变量,2和3谁在前谁先初始化)
具体输出如下:在父类静态变量定义处直接赋值之前的基本类型变量:0 在父类静态变量定义处直接赋值之前的引用类型变量:null 父类静态初始化之前基本类型变量:10 父类静态初始化之前引用类型变量:static super haha 在子类静态变量定义处直接赋值之前的基本类型变量:0 在子类静态变量定义处直接赋值之前的引用类型变量:null 子类静态初始化之前基本类型变量:10 子类静态初始化之前引用类型变量:static sub haha 在父类非静态变量定义处直接赋值之前的基本类型变量:0 在父类非静态变量定义处直接赋值之前的引用类型变量:null 父类初始化之前基本类型变量:5 父类初始化之前引用类型变量:super haha 父类构造函数初始化之前基本类型变量:3 父类构造函数初始化之前引用类型变量:haha 在子类非静态变量定义处直接赋值之前的基本类型变量:0 在子类非静态变量定义处直接赋值之前的引用类型变量:null 子类初始化之前基本类型变量:5 子类初始化之前引用类型变量:sub haha 子类构造器初始化之前基本类型变量:4 子类构造器初始化之前引用类型变量:haha
由输出可以看出,类成员变量初始化顺序为:1、如果第一次调用了类的静态成员或者静态方法,那么JVM就会加载对应类文件,初始化其静态的成员变量,且该初始化操作只执行1次,初始化顺序为:
1.1 JVM进行父类静态成员的默认初始化,引用类型初始化为null,基本类型初始化为0之类的值
1.2 执行在父类静态变量定义处的初始化
1.3 执行父类静态代码块初始化
1,4 按照如上执行子类静态成员初始化
经过如上步骤后,父类和子类的静态成员都已经初始化完成。
2、非静态成员初始化
2.1 JVM进行父类非静态成员的默认初始化,引用类型初始化为null,基本类型初始化为0之类的值
2.2 执行在父类非静态变量定义处的初始化
2.3 执行父类非静态代码块初始化
2.4执行父类构造函数中非静态变量的初始化
2.5按照如上执行子类非静态成员初始化