类加载与实例化,
分享于 点击 14315 次 点评:21
类加载与实例化,
类加载与实例化
基本步骤
类装载分为以下 5 个步骤:
- 加载:根据查找路径找到相应的 class 文件然后导入
- 检查:检查加载的 class 文件的正确性
- 准备:给类中的静态变量分配内存空间
- 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用理解为一个标示,而直接引用直接指向内存中的地址
- 初始化:对静态变量和静态代码块执行初始化工作
加载过程
public class ClassLoadTest {
public static int k = 0;
public static ClassLoadTest t1 = new ClassLoadTest("t1");
public static ClassLoadTest t2 = new ClassLoadTest("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造块");
}
static {
print("静态块");
}
public ClassLoadTest(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
new ClassLoadTest("ClassLoadTest");
}
}
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:ClassLoadTest i=10 n=102
示例分析
- 执行 main 时,先加载所在类,声明静态变量,并初始化静态变量执行静态代码块(按顺序执行)
- 初始化到 t1 时,暂停类加载,先实例化,此时 k=0,而 i,n 都未初始化,系统默认值为 0 初始化 j 时, k 自增为 1,i,n 为0,输出 “1:j i=0 n=0”,n,i 自增为 1 执行代码块,输出 “2:构造块 i=1 n=1”,n,i 自增为 2 执行构造函数,输出 “3:t1 i=2 n=2”,n,i 自增为 3
- 初始化到 t2 时,暂停类加载,先实例化,此时 k=3,i,n 都还未初始化,但已自增为 3 初始化 j 时,k 自增为 4,i,n 未初始化为 3,输出 “4:j i=3 n=3”,n,i 自增为 4 执行代码块,输出 “5:构造块 i=4 n=4”,n,i 自增为 5 执行构造函数,输出 “6:t2 i=5 n=5”,n,i 自增为 6
- 初始化 i,输出 “7:i i=6 n=6”,n,i 自增为 7,返回自增后的i赋值给 i
- 初始化 n,赋值 99
- 执行静态块,输出 “8:静态块 i=7 n=99”,i 自增为 8,n 自增为 100
类加载过程
加载某类前先加载其父类 加载某类时,先声明静态成员变量,初始化为默认值,再初始化静态成员变量执行静态代码块 初始化静态成员变量执行静态代码块时,是按顺序执行(初始化静态成员变量的本质就是静态代码块)
在某类加载过程中调用了本类实例化过程(如new了本类对象),则会暂停类加载过程先执行实例化过程,执行完毕再回到类加载过程
实例化过程
对某类实例化前,先对其父类进行实例化 实例化某类时,先声明成员变量,初始化为默认值,再初始化成员变量执行代码块 初始化成员变量执行代码块时,是按顺序执行
类的主动与被动使用
所有的 JVM 实现,在首次主动使用某类的时候才会加载该类。
- 被动使用场景
- 子类调用父类的静态变量,子类不会被初始化。只有父类被初始化。对于静态字段,只有直接定义这个字段的类才会被初始化
- 通过数组定义来引用类,不会触发类的初始化,如
SubClass[] sca = new SubClass[10]
- 访问类的编译期常量,不会初始化类
编译期常量
变量初始化
byte:0(8位)
short:0(16位)
int:0(32位)
long:0L(64位)
char:\u0000(16位),代表NULL
float:0.0F(32位)
double:0.0(64位)
boolean: flase
- 局部变量声明以后,java 虚拟机不会自动的初始化为默认值
因此对于局部变量,必须先经过显示的初始化,才能使用。如果编译器确认一个局部变量在使用之前可能没有被初始化,编译器将报错
类加载器
分类
graph TB B(Bootstrap ClassLoader)-->E(ExtensionClassLoder) E-->S(Application ClassLoader) S-->U(User-Defined ClassLoder)功能
委派模式
相关文章
- 暂无相关文章
用户点评