
true or false?
有同学在星球问了这样一个问题。
代码是这样的:
最后的输出结果你以为是 true true,其实是 false true。
GPT 表示对于这个问题,他确实无法理解。。。
为了看这个问题的结果,可以反编译看下,执行命令:
得到反编译的字节码结果,结果包含 3 个部分:
1. public com.aixiaoxian.orm.Main() 调用无参构造函数
2. public static void main(java.lang.String[]); main 方法
3. static{} 静态代码
看静态代码部分赋值,13、16 、19,可以很明显的发现 c 和 a 的值都是 true。
然后再看 8 和 6,取值是索引 13 的位置,并没有初始化,所以值应该默认是 false。
那么问题是为什么 b 在初始化的时候为什么没有把 a 的值赋给他呢?
看这个问题我们先复习一下 new 对象的过程。
当虚拟机遇见new关键字时候,实现判断当前类是否已经加载,如果类没有加载,首先执行类的加载机制,加载完成后再为对象分配空间、初始化等。
1. 首先校验当前类是否被加载,如果没有加载,执行类加载机制
2. 加载:就是从字节码加载成二进制流的过程
3. 验证:当然加载完成之后,当然需要校验Class文件是否符合虚拟机规范,跟我们接口请求一样,第一件事情当然是先做个参数校验了
4. 准备:为静态变量、常量赋默认值
5. 解析:把常量池中符号引用(以符号描述引用的目标)替换为直接引用(指向目标的指针或者句柄等)的过程
6. 初始化:执行static代码块(cinit)进行初始化,如果存在父类,先对父类进行初始化
当类加载完成之后,紧接着就是对象分配内存空间和初始化的过程
1. 首先为对象分配合适大小的内存空间
2. 接着为实例变量赋默认值
3. 设置对象的头信息,对象hash码、GC分代年龄、元数据信息等
4. 执行构造函数(init)初始化
在这个代码中,首先先要执行类的初始化,类初始化过程中去给静态变量、常量赋值,之后再去给实例变量赋值,按照道理来说 b 应该也是 true 才对。
问题其实出现在代码顺序上,第一行代码就是去 new 一个静态的 Main 实例对象,但是这里代码顺序先去初始化 instance ,但是此时代码 a 的定义写在 instance 之后,所以初始化 instance 对象的时候其实 a 还没有赋值,所以给 b 赋值的时候就是 false。
所以这里的代码只要调整一下顺序,把private static boolean a = initA();
放到第一行,结果就会变成 true 了。
好了好了,就这样,都散了吧。
文章转载自公众号:艾小仙
