问题引入
class MyObject {
static int num1 = 100;
static int num2 = 100;
static MyObject myObject = new MyObject();
public MyObject() {
num1 = 200;
num2 = 200;
}
@Override
public String toString() {
return num1 + "\t" + num2;
}
}
class MyObject2 {
static int num1 = 100;
static MyObject2 myObject2 = new MyObject2();
public MyObject2() {
num1 = 200;
num2 = 200;
}
static int num2 = 100;
@Override
public String toString() {
return num1 + "\t" + num2;
}
}
public class ClassLoadingProcessStatic {
public static void main(String[] args) {
System.out.println(MyObject.myObject);
System.out.println(MyObject2.myObject2);
}
}
两个结果分别是什么?一样吗?都是200 200吗?
类的加载过程
类的生命周期:
加载 ——> 连接 ——> 初始化 ——> 使用 ——> 卸载
连接阶段又分为:验证——>准备——>解析
总的看:加载 ——> 验证 ——> 准备 ——> 解析 ——> 初始化 ——> 使用 ——> 卸载
准备阶段
为类的静态变量分配内存,并将其赋默认值
对static修饰的静态变量进行内存分配、赋默认值(如0、0L、null、false等)。
注意:对final的静态字面值常量直接赋初值,即字面值
初始化阶段
为类的静态变量赋初始值
解答
这样,就可以走一下上面那题的流程了
第一个输出结果:
-
准备阶段:
num1:0
num2:0
myObject:null -
初始化阶段:
num1:0变成100
num2:0变成100
myObject:null变成一个内存地址,同时执行构造方法:num1,100变成200;num2,100变成200 -
所以最终输出结果:
200 200
第二个输出结果:
-
准备阶段:
num1:0
myObject:null
num2:0 -
初始化阶段:
num1:0变成100
myObject:null变成一个内存地址,同时执行构造方法:num1,100变成200;num2,0变成200
num2:200变成100 -
所以最终输出结果:
200 100
- 本质区别就是,num2的初始化阶段会在执行了构造方法之后,因为静态变量的加载是按照顺序的
注意
正确理解类加载过程中的准备阶段和初始化阶段,看清楚静态变量和构造方法的先后