In a comment to this question, I'm claiming that final
in some cases must be honored by the JVM. The safe publication of final
variables has been already asked and so was the handling of static final members. But what about enforcing classes and methods being final and forbidding overwriting of final fields? IMHO this can and must be done at class loading time.
My argument is that
- For the security of the JVM is crucial that e.g.
String
is final
, so a hand-crafted class extending it must not be loaded.
- Similarly for
public final
fields. While reflection can change them, it's checked at runtime. Therefore a bytecode reassigning final fields must be rejected when loaded, too.
But I couldn't find a proof. Am I right?
Yes, you're right.
For classes marked as final
, see The Java Virtual Machine Specification: Java SE 8 Edition, §4.10 "Verification of class
Files", which says in part:
[…] the Java Virtual Machine needs to verify for itself that the desired constraints are satisfied by the class
files it attempts to incorporate. A Java Virtual Machine implementation verifies that each class file satisfies the necessary constraints at linking time (§5.4).
[…]
[…] there are three additional checks outside the Code
attribute which must be performed during verification:
- Ensuring that
final
classes are not subclassed.
- […]
(See there for many more details, including what the JVM is supposed to do when a class
file violates this constraint.)
For fields marked as final
, see ibid., §§6.5–6 "putfield
" and "putstatic
", which say in part of putfield
:
Otherwise, if the field is final
, it must be declared in the current class, and the instruction must occur in an instance initialization method (<init>
) of the current class. Otherwise, an IllegalAccessError
is thrown.
and likewise of putstatic
, but with "the <clinit>
method" instead of "an instance initialization method (<init>
).
(As you may have guessed, putfield
and putstatic
are the bytecode instructions for setting instance and static fields, respectively.)