แม้จะfinal
เป็นเขตข้อมูลก็สามารถแก้ไขได้นอก static initializer และ (อย่างน้อย JVM HotSpot) จะดำเนินการ bytecode ได้อย่างสมบูรณ์แบบ
ปัญหาคือว่า Java คอมไพเลอร์ไม่อนุญาตให้นี้ objectweb.asm
แต่สามารถข้ามได้อย่างง่ายดายโดยใช้ นี่คือไฟล์คลาสที่ถูกต้องสมบูรณ์แบบที่ผ่านการตรวจสอบ bytecode และโหลดสำเร็จและเริ่มต้นภายใต้ JVM HotSpot OpenJDK12:
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Cl", null, "java/lang/Object", null);
{
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "fld", "I", null, null);
fv.visitEnd();
}
{
// public void setFinalField1() { //... }
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField1", "()V", null, null);
mv.visitMaxs(2, 1);
mv.visitInsn(Opcodes.ICONST_5);
mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
{
// public void setFinalField2() { //... }
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField2", "()V", null, null);
mv.visitMaxs(2, 1);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
cw.visitEnd();
ใน Java ชั้นเรียนจะพูดคร่าวๆดังนี้
public class Cl{
private static final int fld;
public static void setFinalField1(){
fld = 5;
}
public static void setFinalField2(){
fld = 2;
}
}
ซึ่งไม่สามารถคอมไพล์ด้วยjavac
แต่สามารถโหลดและดำเนินการโดย JVM
JVM HotSpot ได้รับการดูแลเป็นพิเศษจากคลาสดังกล่าวในแง่ที่ว่าจะป้องกัน "ค่าคงที่" ดังกล่าวจากการเข้าร่วมการพับแบบคงที่ การตรวจสอบนี้ทำในขั้นตอนการเขียนทับ bytecode ของการเริ่มต้นคลาส :
// Check if any final field of the class given as parameter is modified
// outside of initializer methods of the class. Fields that are modified
// are marked with a flag. For marked fields, the compilers do not perform
// constant folding (as the field can be changed after initialization).
//
// The check is performed after verification and only if verification has
// succeeded. Therefore, the class is guaranteed to be well-formed.
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
fieldDescriptor fd;
if (klass->find_field(field_name, field_sig, &fd) != NULL) {
if (fd.access_flags().is_final()) {
if (fd.access_flags().is_static()) {
if (!method->is_static_initializer()) {
fd.set_has_initialized_final_update(true);
}
} else {
if (!method->is_object_initializer()) {
fd.set_has_initialized_final_update(true);
}
}
}
}
}
}
ข้อ จำกัด เดียวที่ JVM HotSpot ตรวจสอบคือfinal
ฟิลด์ไม่ควรแก้ไขนอกคลาสที่final
ประกาศฟิลด์