为什么对象调用 toString() 会影响对象头的输出?我正在使用 jol 包

Why does the object call toString() affect the output of the object header? I am using the jol package

L的代码很简单

public class L {
}

public class Synchronized1 {
    public static void main(String[] args) {
        L l=new L();
//       System.out.println(l.toString());
       System.out.println(ClassLayout.parseInstance(l).toPrintable());
    }
}

取消注释,运行再次代码将导致不同的结果,或两个完全不同的结果。我想知道这个结果的原因是什么? 不仅仅是调用 toString() 会影响结果,调用对象上的其他方法也会影响结果,例如 hashCode()

您的空 class class L 使用继承自 class Object 的默认 toString()

默认 toString() 调用 hashCode().

正如您已经看到的,hashCode() 似乎也影响了 object 的 header。

所以,本质上,问题可以重述为"Why does calling hashCode() alter the header of my object?"

正如其他人已经在评论中指出的那样,发生这种情况是因为在您使用的特定 JVM 实现中,object 的 hashCode 是在第一次调用 hashCode() 时计算的,然后它被缓存在 header 中,这样后续对 hashCode() 的调用就可以 return 缓存的值,而不必再次 re-compute 它。

除了性能,这样做还有一个更重要的原因。

根据您使用的 JVM 计算哈希码的方式,计算中可能涉及随机性,或者可能存在 ever-incrementing 数字种子,因此可能是后续尝试重现哈希码object 的计算将无法生成与第一次计算完全相同的值。这意味着第一次计算必须确定 hashcode 值将永远是什么。