java - 使用 Java 反射更改私有(private)静态最终字段

标签 java reflection static private final

我有一个带有 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通过 Boolean.TRUE
  • 以前“假”的一切现在都是“真”

相关问题


注意事项

每当你做这样的事情时,都应该格外小心。它可能无法工作,因为可能存在 SecurityManager,但即使它不存在,根据使用模式,它也可能会或可能不会工作。

JLS 17.5.3 Subsequent Modification of Final Fields

In some cases, such as deserialization, the system will need to change the final fields of an object after construction. final fields can be changed via reflection and other implementation dependent means. The only pattern in which this has reasonable semantics is one in which an object is constructed and then the final fields of the object are updated. The object should not be made visible to other threads, nor should the final fields be read, until all updates to the final fields of the object are complete. Freezes of a final field occur both at the end of the constructor in which the final field is set, and immediately after each modification of a final field via reflection or other special mechanism.

Even then, there are a number of complications. If a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the compile-time constant.

Another problem is that the specification allows aggressive optimization of final fields. Within a thread, it is permissible to reorder reads of a final field with those modifications of a final field that do not take place in the constructor.

另见

  • > JLS 15.28 Constant Expression
    • 这种技术不太可能与原始 private static final boolean 一起使用,因为它可以作为编译时常量内联,因此可能无法观察到"new"值

附录:关于按位操作

本质上,

field.getModifiers() & ~Modifier.FINAL

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

另见


记住常量表达式

还是无法解决这个问题?,像我一样陷入抑郁症?您的代码看起来像这样吗?

public class A {
    private final String myVar = "Some Value";
}

阅读对此答案的评论,特别是@Pshemo 的评论,它提醒我 Constant Expressions处理方式不同,因此不可能对其进行修改。因此,您需要将代码更改为如下所示:

public class A {
    private final String myVar;

    private A() {
        myVar = "Some Value";
    }
}

如果您不是类(class)的所有者...我能感觉到您!

有关此行为原因的更多详细信息 read this

关于java - 使用 Java 反射更改私有(private)静态最终字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15856632/

相关文章:

java - 将 BoundMethodHandle 转换为反射

java - Eclipse 组织静态导入

java - 如何获取以下代码的输出?

java - 从语言代码中获取该语言的语言名称

java - 将最新版本从 SVN 发送到 Tomcat6 webapp 目录

java - 使用 Java Reflection 在运行时获取字段及其值

c++ - 共享库中是否应该避免使用静态成员函数?

java - 如何从 Java 中的 UTF-8 字符串中替换/删除 4(+) 字节字符?

Java Android 相机

java - 如何检查 "multi-object"返回类型