-
合集目录
- Java语法专题2: 类变量的初始化顺序
问题
这也是Java面试中出镜率很高的基础概念问题
- 描述一下多级继承中字段初始化顺序
- 描述一下多级继承中类变量初始化顺序
- 写出运行以下代码时的控制台输出
public class Base {
public static int v1 = method(1);
private static int v2 = method(2);
private int v3;
private int v4 = method(3);
public Base() {
v3 = method(4);
}
public static int method(int i) {
System.out.println(i);
return i;
}
public static void main(String args[]) {
method(5);
Base b2 = new Base();
}
}
分析
正确回答这些问题, 需要对以下的概念有了解:
-
static
关键字, 静态变量和静态方法 - 静态变量和普通成员变量初始化的区别
- 类初始化中父类和子类变量的初始化顺序
以下通过具体场景说明
场景一: 单个类的初始化顺序
先看单个类的初始化顺序, 静态和普通变量都根据public和private区分, 交替声明.
Base.java
public class Base {
public static int pub_s = method(1);
private static int pri_s = method(2);
public static int pub_s2 = method(3);
private static int pri_s2 = method(4);
private int pri1;
private int pri2 = method(5);
private int pri3;
private int pri4 = method(6);
public Base() {
pri1 = method(7);
pri3 = method(8);
}
public static int method(int i) {
System.out.println(i);
return i;
}
public static void main(String args[]) {
method(0);
Base b2 = new Base();
}
}
输出结果为
1
2
3
4
0
5
6
7
8
可以得到以下信息
- 静态成员变量初始化最早
- 与实例初始化无关, 在载入类时完成初始化
- 初始化顺序与代码顺序一致, 与public还是private无关
- 静态成员变量初始化在执行main()函数之前完成, 因为在执行main()函数前, 静态成员初始化就伴随类的载入完成了
- 普通成员变量初始化在执行构造函数之前
场景二: 带继承关系的类初始化顺序
保持Base.java不变, 增加Sub.java作为子类
Sub.java
public class Sub extends Base {
public static int sub_pub_s = method(11);
private static int sub_pri_s = method(12);
public static int sub_pub_s2 = method(13);
private static int sub_pri_s2 = method(14);
private int sub_pri1;
private int sub_pri2 = method(15);
private int sub_pri3;
private int sub_pri4 = method(16);
public Sub() {
sub_pri1 = method(17);
sub_pri3 = method(18);
}
public static void main(String args[]) {
method(10);
Sub b2 = new Sub();
}
}
运行Sub.java, 输出结果为
1
2
3
4
11
12
13
14
10
5
6
7
8
15
16
17
18
可以得到以下信息
- 在任何情况下, 静态成员变量都会最先初始化
- 在存在继承关系的类中, 父类的静态成员变量先初始化, 然后是子类的静态成员变量
- 所有静态成员变量初始化之后, 才开始main函数的执行
- 在类实例初始化过程中, 先初始化父类, 再初始化子类, 每一层都是先成员变量, 然后执行构造函数, 所以顺序就是: 父类成员变量, 父类构造函数, 子类成员变量, 最后是子类构造函数
总结
类的构造顺序为
- 父类静态成员变量, 其顺序与代码顺序一致, 与public还是private无关
- 子类静态成员变量, 其顺序与代码顺序一致, 与public还是private无关
- 如果执行类的静态函数(包括main函数), 这个时间点就会开始执行函数
- 如果创建了类的实例, 注意这个前提, 下面就会开始普通成员变量的初始化
- 父类的普通成员变量
- 父类的构造函数
- 子类的普通成员变量
- 子类的构造函数