最终静态与最终非静态字段和 JVM 优化

final static vs final non-static fields and JVM optimization

我很好奇 JVM 如何处理 static final 字段。我看到了一个类似的问题 here 但这不是我要找的。让我们考虑这样的例子:

public class TestClassX {
   public final int CODE_A = 132;
   public final int CODE_B = 948;
   public final int CODE_C = 288;
   // some other code
}

public class TestClassY {
   public static final int CODE_A = 132;
   public static final int CODE_B = 948;
   public static final int CODE_C = 288;
   // some other code
}

TestClassX 字段中,因为它们是 final 且无法修改,所以在 TestClassX class 的所有实例中具有相同的值。当然我不能写 TestClassX.CODE_A 但我可以说,这些值实际上对所有实例都是通用的 - 我敢肯定,每个实例都有一个 CODE_A 字段,其值为 132

TestClassY 中,我可以使用语法 TestClassY.CODE_A,但乍一看,对于看到 "Oh, those values are common for all instances".

的开发人员来说,这只会更容易

我的主要问题: 我猜 JVM 在 TestClassX 的情况下不会在每次创建新实例时为 final 字段使用任何额外的内存。可以? JVM在这种情况下有没有做优化,是什么优化?

附加问题 1) 我也确定我在这里遗漏了一些非常重要的东西,这是我怀疑的原因。那是什么?

附加问题 2) 顺便说一句。如何查看我的 Java 源代码在 JVM 优化后的样子(以便我将来可以使用 ;))? IDE 是否支持这样的功能?例如 IntelliJ?我只想看看 JVM 如何对待我的 TestClassXTestClassY.

对于你问题的第一部分,也许this answer可以帮到你。

对于第二部分,您可以通过在 run/compile 代码中添加 -XX:+PrintOptoAssembly 标志来查看生成的程序集(如 this answer 中所述)。

我还要补充一点,给你的汇编代码不是jvm生成的真正的操作码,而是需要在你的运行下的代码 实际架构。

希望对您有所帮助!

  • 实例中始终存在非静态字段。它们不节省内存。
  • 一般来说,JVM 不会优化非静态字段。即使它们是最终的,它们仍然可以使用反射或在反序列化期间设置为不同的值。
  • 有一个实验性 VM 选项 -XX:+TrustFinalNonStaticFields(默认情况下关闭)告诉 JVM 优化对此类字段的访问,即将它们视为常量并消除字段负载。
  • 有一个 -XX:+PrintAssembly VM 选项可以转储 JIT 编译的代码。