由JVM处理`final`
在对这个问题的评论中,我声称在某些情况下final
必须得到JVM的尊重。 已经提出了final
变量的安全发布 , 静态最终成员的处理也是如此。 但是如何强制执行最终的类和方法并禁止覆盖最终字段呢? 恕我直言,这可以而且必须在上课时间完成。
我的论点是
- 因为JVM的安全性至关重要,例如
String
是final
,所以不得加载扩展它的手工制作的类。 - 同样适用于
public final
字段。 虽然reflection可以改变它们,但它会在运行时进行检查。 因此,加载时必须拒绝重新分配最终字段的字节码。
但我找不到证据。 我对吗?
你是对的。
对于标记为final
类,请参阅Java虚拟机规范:Java SE 8 Edition ,§4.10“ class
文件validation” ,其中部分说明:
[…] Java虚拟机需要自己validation它尝试合并的
class
文件是否满足所需的约束。 Java虚拟机实现validation每个类文件是否满足链接时的必要约束(第5.4节 )。[…]
[…]在
Code
属性之外还有三个额外的检查,必须在validation期间执行:
- 确保
final
类不是子类。- […]
(有关更多详细信息,请参阅此处,包括当class
文件违反此约束时JVM应执行的操作。)
对于标记为final
字段,请参阅同上,§§6.5-6“ putfield
”和“ putstatic
” ,其中部分为putfield
:
否则,如果该字段是
final
,则必须在当前类中声明,并且该指令必须在当前类的实例初始化方法()中进行。 否则,
IllegalAccessError
。
同样也是putstatic
,但是用“
方法”代替“实例初始化方法(
)。
(正如您可能已经猜到的那样, putfield
和putstatic
分别是用于设置实例和静态字段的字节码指令。)