使用反射设置私有静态最终字段

Pau*_*per 5 java reflection

基于使用Java反射更改私有静态最终字段,我尝试设置私有静态最终字段.

(我知道这非常hacky,但这个问题不是关于代码质量;而是关于Java反射.)

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

class Main {

  static class Foo {
    private static final int A = 1;

    int getA() {
      return A;
    }
  }

  public static void main(String[] args) throws Exception {
    Field modifiers = Field.class.getDeclaredField("modifiers");
    modifiers.setAccessible(true);

    Field field = Foo.class.getDeclaredField("A");
    field.setAccessible(true);
    modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, 2);

    System.out.println(new Foo().getA()); // should print 2
  }

}
Run Code Online (Sandbox Code Playgroud)

这打印

1
Run Code Online (Sandbox Code Playgroud)

我已经尝试过使用OpenJDK 6和7以及Oracle 7.

我不知道Java反射给出了什么.但如果它失败了,我以为会有Exception(实际上所有的反射方法都会抛出异常).

这里发生了什么?

Mik*_*uel 9

Java内final在编译时初始化为常量表达式的字段.

根据Java语言规范,任何使用可在编译时计算的表达式初始化的static final*字段必须编译为"内联"字段值的字节代码.也就是说,类中没有动态链接,Main告诉它在运行时获取Afrom 的值InterfaceA.

反编译字节码,你会发现getA()简单地推动常量1并返回它.


* - JavaWorld的报价说static final.Kumar指出,在常量变量的定义中,语言规范static并不要求它.我认为库马尔是正确的,JavaWorld是错误的.

  • +1 OP,它没有_fail_.试试`System.out.println(field.get(null)); //应该打印2` (3认同)
  • 另外http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3 (2认同)