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 与所引用的相同by Boolean.TRUE
  • 所有以前的 "false" 现在都是 "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/3301635/

相关文章:

java - 列出 Azure 中(子)目录中的所有文件

java - 如何在 Apache Ignite 中查找正在运行的服务器或客户端 IP 及其端口

java - 将 TIMESTAMP 列从 PostgreSQL 映射到 LocalDate

Java:如何提取注解成员

rust - 特征对象的静态数组

java - Junit 5标签不适用于Gradle 6.5.1

c# - 如何在 C# 中的运行时向类添加属性?

php - PHP 中类型安全的通用装饰器

c++ - 不理解静态 boolean 行为

c++ - 有没有办法在不破坏封装的情况下为模板类(所有类型)使用一个静态变量