Java类加载时机与过程
文章部分内容引用于:
从一道面试题来认识java类加载时机与过程
增加了一些自己的理解。
由一个题目引出
写出下面代码的输出
1 |
|
看起来像简单的单例类,但要注意count1与count2都是静态变量。
错误的结果:
1 |
|
正确答案:
1 |
|
为什么呢?
分析
静态变量顺序初始化,先初化singleTon,调用count1++,count2++。
再初始化count2 = 0。于是count2在构造函数里面累加被重置了。
如果把声明顺序调换下。
比如
1 |
|
则结果会是
1 |
|
产生上面1
,0
的原因就是 类加载的时 分配内存并初始化默认值 与 类初始化时 静态变量赋值和执行静态代码块,要分开看。
类的加载过程
类从被加载到虚拟机内存中开始,直到卸载出内存为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)。
何时开始类的初始化
主动引用
什么情况下需要开始类加载过程的第一个阶段:”加载”。虚拟机规范中并没强行约束,这点可以交给虚拟机的的具体实现自由把握,但是对于初始化阶段虚拟机规范是严格规定了如下几种情况,如果类未初始化会对类进行初始化。
- 创建类的实例
- 访问类的静态变量
- 访问类的静态方法
- 反射如(Class.forName(“com.xx.Main”))
- 当初始化一个类时,发现其父类还未初始化,则先触发父类的初始化
- 虚拟机启动时,定义了main()方法的那个类先初始化
以上情况称为称对一个类进行“主动引用”,除此种情况之外,均不会触发类的初始化,称为“被动引用”
被动引用
被动引用例子:
- 子类调用父类的静态变量,子类不会被初始化。只有父类被初始化。。对于静态字段,只有直接定义这个字段的类才会被初始化.
- 通过数组定义来引用类,不会触发类的初始化
- 访问类的常量,不会初始化类
类的加载过程
- 加载
- 验证
- 准备
- 解析
- 初始化
更多参考
Java类加载时机与过程
https://blog.fengcl.com/2017/09/08/java-class-loading-time-and-process/