【问题标题】:Handling of `final` by the JVMJVM对`final`的处理
【发布时间】:2015-05-16 17:37:32
【问题描述】:

在对此question 的评论中,我声称final 在某些情况下必须得到JVM 的认可。已经询问了final 变量的safe publicationhandling of static final members。但是强制类和方法是最终的并禁止覆盖最终字段呢?恕我直言,这可以而且必须在类加载时完成。

我的观点是

  • 对于 JVM 的安全性至关重要,例如Stringfinal,因此不得加载扩展它的手工类。
  • public final 字段也是如此。虽然反射可以改变它们,但它会在运行时进行检查。因此,在加载时也必须拒绝重新分配最终字段的字节码。

但我找不到证据。我说的对吗?

【问题讨论】:

    标签: java jvm final


    【解决方案1】:

    是的,你是对的。


    对于标记为final 的类,请参阅The Java Virtual Machine Specification: Java SE 8 Edition, §4.10 "Verification of class Files",其中部分内容是:

    [...] Java 虚拟机需要自己验证它尝试合并的class 文件是否满足所需的约束。 Java 虚拟机实现验证每个类文件在链接时满足必要的约束 (§5.4)。

    […]

    [...] 在验证期间必须执行 Code 属性之外的三项额外检查:

    • 确保final 类不是子类。
    • […]

    (请参阅那里了解更多详细信息,包括当class 文件违反此约束时JVM 应该做什么。)


    对于标记为final 的字段,请参阅ibid., §§6.5–6 "putfield" and "putstatic",其中部分内容为putfield

    否则,如果字段为final,则必须在当前类中声明,且指令必须出现在当前类的实例初始化方法(<init>)中。否则,将抛出 IllegalAccessError

    同样适用于putstatic,但使用“<clinit> 方法”而不是“实例初始化方法 (<init>)。

    (你可能已经猜到了,putfieldputstatic 分别是设置实例和静态字段的字节码指令。)

    【讨论】:

    • 这完美地涵盖了我的第一颗子弹,但我找不到第二颗子弹的任何证据。我想,分配Integer.MAX_VALUE = -1 对大多数服务器来说将是一场灾难,但看不出它是如何预防的。
    • @maaartinus:我的错;我没有注意到你问的是两种不同的final。这可以说是两个独立的问题(您当前的问题有点像询问 JVM 是否强制执行 private@Override),但是,好的,我已经更新了我的答案以涵盖两者。
    • 我的错,这确实应该是两个问题(但是 OTOH 在 JVM 中有一个涵盖关于 final 的所有内容的地方更适合搜索)。我找不到它,因为我不知道它发生在链接阶段(这实际上是完全合乎逻辑的)。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 2021-03-04
    • 2011-06-15
    • 2023-03-22
    相关资源
    最近更新 更多