我无法理解可能无法观察到对最终字段的更改
它表明,如果将最终变量声明为编译时间常数,则在执行过程中,程序中进一步使用 反射API 对最终变量进行的任何更改将对程序不可见。
例如,考虑以下代码:
import java.lang.reflect.*;class ChangeFinal { private final int x = 20;//compile time constant public static void change(ChangeFinal cf) { try { Class clazz = ChangeFinal.class; Field field = clazz.getDeclaredField("x"); field.setAccessible(true); field.set(cf , 190);//changed x to 190 for object cf } catch (Exception ex) { ex.printStackTrace(); } } public static void main(String[] args) { ChangeFinal cf = new ChangeFinal(); System.out.println(cf.x);//prints 20 change(cf); System.out.println(cf.x);//prints 20 }}上面代码的输出是:
2020
为什么?
答案在于
javap -c命令为公共静态void main 提供的输出:
public static void main(java.lang.String[]); Code: 0: new #3; //class ChangeFinal 3: dup 4: invokespecial #11; //Method "<init>":()V 7: astore_1 8: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream; 11: aload_1 12: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Class; 15: pop 16: bipush 20 18: invokevirtual #14; //Method java/io/PrintStream.println:(I)V 21: aload_1 22: invokestatic #15; //Method change:(LChangeFinal;)V 25: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream; 28: aload_1 29: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Class; 32: pop 33: bipush 20 35: invokevirtual #14; //Method java/io/PrintStream.println:(I)V 38: return}
在第16行(在
changeFinal调用方法之前),将的值
cf.x硬编码为
20。在第33行(
changeFinal调用方法之后)的值
cf.x再次被硬编码为
20。因此,尽管最终变量值的更改
x是通过
reflectionAPI在执行期间成功完成的 ,但是由于
x是编译时常量,因此它显示了其常量值
20。



