修改Java中的最终字段

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (9)

我们从一个简单的测试用例开始:

import java.lang.reflect.Field;

public class Test {
  private final int primitiveInt = 42;
  private final Integer wrappedInt = 42;
  private final String stringValue = "42";

  public int getPrimitiveInt()   { return this.primitiveInt; }
  public int getWrappedInt()     { return this.wrappedInt; }
  public String getStringValue() { return this.stringValue; }

  public void changeField(String name, Object value) throws IllegalAccessException, NoSuchFieldException {
    Field field = Test.class.getDeclaredField(name);
    field.setAccessible(true);
    field.set(this, value);
    System.out.println("reflection: " + name + " = " + field.get(this));
  }

  public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
    Test test = new Test();

    test.changeField("primitiveInt", 84);
    System.out.println("direct: primitiveInt = " + test.getPrimitiveInt());

    test.changeField("wrappedInt", 84);
    System.out.println("direct: wrappedInt = " + test.getWrappedInt());

    test.changeField("stringValue", "84");
    System.out.println("direct: stringValue = " + test.getStringValue());
  }
}

问题是:

  1. 为什么原始和包装整数的行为不同?
  2. 为什么反射与直接访问返回不同的结果?
  3. 最让我感到困扰的 - 为什么String的行为像原始int而不是像Integer

结果(java 1.5):

reflection: primitiveInt = 84
direct: primitiveInt = 42
reflection: wrappedInt = 84
direct: wrappedInt = 84
reflection: stringValue = 84
direct: stringValue = 42
提问于
用户回答回答于

编译时常量是内联的(在javac编译时)。请参阅JLS,特别是15.28定义了一个常量表达式,13.4.9讨论了二进制兼容性或最终字段和常量。

如果将该字段设置为非最终值或指定一个非编译时间常量,则该值不会内联。例如:

private final String stringValue = null!= null?“”:“42”;

用户回答回答于

在我看来,这更糟糕:一位同事指出了以下有趣的事情:

@Test public void  testInteger() throws SecurityException,  NoSuchFieldException, IllegalArgumentException, IllegalAccessException  {      
    Field value = Integer.class.getDeclaredField("value");      
    value.setAccessible(true);       
    Integer manipulatedInt = Integer.valueOf(7);      
    value.setInt(manipulatedInt, 666);       
    Integer testInt = Integer.valueOf(7);      
    System.out.println(testInt.toString());
}

通过这样做,可以更改所运行的整个JVM的行为(当然,只能更改-127和127之间的值的值)

扫码关注云+社区