使用Java反射更改私有静态最终字段

问题:

我有一个private static final字段的类,不幸的是,我需要在运行时更改。
使用反射我得到这个错误:java.lang.IllegalAccessException: Can not set static final boolean field
有没有办法改变价值?

Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);

回答:

假设没有SecurityManager阻止您这样做,您可以使用setAccessible绕过private并重置修饰符以摆脱final,实际修改private static final字段。
这里有一个例子:

import java.lang.reflect.*;

public class EverythingIsTrue {
   static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }
   public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getField("FALSE"), true);

      System.out.format("Everything is %s", false); // "Everything is true"
   }
}

假设没有SecurityException被抛出,上面的代码打印"Everything is true"
这里实际做的如下:

  • main中的原始booleantruefalse被自动装箱以引用类型Boolean“常量”Boolean.TRUEBoolean.FALSE
  • 反射用于将public static final Boolean.FALSE改变为Boolean.TRUE引用的Boolean
  • 结果,随后false自动装箱到Boolean.FALSE时,它指的是与Boolean.TRUE所指的Boolean相同的Boolean
  • 现在"false"的所有内容都是"true"

相关问题

注意事项

当你做这样的事情时,应该非常小心。它可能无法工作,因为SecurityManager可能存在,但即使没有,根据使用模式,它可能或可能不工作。

 JLS 17.5.3 Subsequent Modification of Final Fields
在某些情况下,如反序列化,系统在构建后需要更改对象的final字段。 final字段可以通过反射和其他依赖实现的方式进行更改。唯一具有合理语义的模式是构建对象,然后更新对象的final字段。对象不应该对其他线程可见,也不应该读取final字段,直到对象的final字段的所有更新完成为止。 final字段的冻结都在设置final字段的构造函数的末尾,并且在每次通过反射或其他特殊机制修改final字段之后立即出现。
即使如此,还有一些并发症。如果final字段在字段声明中初始化为编译时常量,则可能无法观察到final字段的更改,因为使用该final字段在编译时被替换为编译时常数。
另一个问题是规范允许对final字段的积极优化。在一个线程中,允许使用在构造函数中不发生的最终字段的修改来重新排序final字段的读取。

也可以看看

  •  JLS 15.28 Constant Expression
     

    • It’s unlikely that this technique works with a primitive private static final boolean, because it’s inlineable as a compile-time constant and thus the “new” value may not be observable

附录:按位操作

从本质上讲,

field.getModifiers() & ~Modifier.FINAL

关闭field.getModifiers()中与Modifier.FINAL对应的位。 &是按位的,~是按位补码。

也可以看看

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: Change private static final field using Java reflection

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

3 + 7 =