Java中类的生命周期(快速掌握)
概览
加载阶段
第一步
我们也可以使用Java代码拓展不同的渠道
第二步
第三步
这里的InstanceKlass是区别与源代码中的Class
第四步
方法区中的Klass对象,是使用C++所编写出来的对象,一般不能够直接进行操作,并且其中有部分信息,开发者在开发时并不是经常用的到,所以就在堆区中又创建了一个Class对象,该Class对象在反射中尤为重要
这样也能很好的控制开发者访问数据的范围,为数据安全做保障
连接阶段
验证
这里只罗列了四部分,但是真实验证的内容远远不止这些
准备
准备阶段为静态变量(static)分配内存并且设置初始值(这里以JDK8之后的版本为例)
例如,有如下代码
public static int i=1;
在准备阶段,会为 i 这个变量设置默认值0,赋值为1的操作并不在该阶段,而是在下一个阶段
这里给出大部分类型的默认初始值
- 注意:有一个特殊情况,如果静态变量使用final修饰,那么在该阶段会直接为该变量赋值
例如,有如下代码
public static final int i=1;
这里又final修饰,会直接将 i 赋值为1,不会赋给 i 默认值0
解析
- 直接引用就是常说的内存地址的引用
初始化
概览
例子如下,
这里最终value的值为2
思考一个问题,如果将该静态代码块放到声明该变量之前会发生什么?答案是,value的值将被赋值为1
我们从字节码指令的角度来看,为什么会是这样的结果
- 会发现,iconst_1与iconst_2的字节码命令的执行顺序发生了改变
那么,就有一个结论——clinit方法中的执行顺序与Java代码中编写的顺序是一致的
类的初始化的方式
- 注意:clinit指令在某些特定的情况下不会执行
- 在继承中的clinit指令执行情况
题目练手
第一道
这里最终会在控制台输出DACBCB
首先由于main方法要执行,所以会加载Test1这个类,那么就会执行静态代码块中的代码,输出D。然后,开始执行main方法,输出A。接着 new 了两个Test1对象,由于Test1这个类在之前已经加载过了,所以不会重复加载,自然也就不会再打印D了。new Test1会执行该类的构造方法,打印 “C” 的语句最终会被整合到构造方法中,并且放在打印“B”的前面(这个大家可以根据字节码指令,或者自行搜索相关资料来了解一下),所以就是输出 “C” “B”,由于是 new 了两个Test1,所以就执行两遍打印“C” “B”。最终的答案就是,输出“DACBCB”
第二道
new B02,首先会优先初始化父类,那么a=1,然后再接着初始化子类,a=2,所以最终答案是a=2
- 拓展一下,如果将new B02()去掉,又会是什么结果呢?
B02.a 访问的是父类A02中的静态变量a(因为a这个变量就是父类A02的中的变量),所以最终a=1
标签:Test1,生命周期,Java,变量,代码,new,执行,中类 From: https://blog.csdn.net/AIAIAIXIAO_/article/details/143242938