java - 有什么方法可以从类外修改 Java 中 `private static final` 字段的值吗?

标签 java monkeypatching

我知道这通常很愚蠢,但在阅读问题之前不要开枪。我保证我有充分的理由需要这样做:)

可以使用反射修改 java 中的常规私有(private)字段,但是当尝试对 final 字段执行相同操作时,Java 会抛出安全异常。

我假设这是严格执行的,但我想无论如何我都会问,以防万一有人想出了一个黑客来做到这一点。

假设我有一个带有“SomeClass”类的外部库

public class SomeClass 
{
  private static final SomeClass INSTANCE = new SomeClass()

  public static SomeClass getInstance(){ 
      return INSTANCE; 
  }

  public Object doSomething(){
    // Do some stuff here 
  }
} 

我基本上想要 Monkey-Patch SomeClass 以便我可以执行我自己的 doSomething() 版本。由于(据我所知)没有任何方法可以在 Java 中真正做到这一点,我在这里唯一的解决方案是更改 INSTANCE 的值,以便它返回我的类版本和修改后的方法。

本质上,我只想用安全检查包装调用,然后调用原始方法。

外部库总是使用 getInstance() 来获取此类的实例(即它是一个单例)。

编辑:澄清一下,getInstance() 是由外部库调用的,而不是我的代码,因此仅子类化无法解决问题。

如果我做不到,我能想到的唯一其他解决方案是复制粘贴整个类并修改方法。这并不理想,因为我必须使我的 fork 与库的更改保持同步。如果有人有更易于维护的东西,我愿意接受建议。

最佳答案

这是可能的。我用它来 monkeypatch 顽皮的 threadlocals,它们阻止了 webapps 中的类卸载。你只需要用反射去掉final修饰符,就可以修改字段了。

像这样的东西就可以了:

private void killThreadLocal(String klazzName, String fieldName) {
    Field field = Class.forName(klazzName).getDeclaredField(fieldName);
    field.setAccessible(true);  
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    int modifiers = modifiersField.getInt(field);
    modifiers &= ~Modifier.FINAL;
    modifiersField.setInt(field, modifiers);
    field.set(null, null);
}

Field#set 也有一些缓存,所以如果某些代码之前运行过,它可能不一定能工作....

关于java - 有什么方法可以从类外修改 Java 中 `private static final` 字段的值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/767008/

相关文章:

ruby - 在模块中打开类

python - 扩展类(Monkey Patching)如何在 Python 中工作?

Java BufferedImage如何知道一个像素是否透明

java - JTree TreeCellRenderer 在显示选择颜色时引发问题

java - 了解 Ringdroid 代码 + Android

c++ - Lua + SWIG 猴子补丁

ruby-on-rails - 为什么 null monkeypatch 会删除迁移中的方法而不是 Rails 控制台中的方法?

Java打印。使用 `Book` 类时仅打印一页

java - 在java中将 boolean 对象转换为字符串的最佳方法

python - Monkeypatching 不进行类导入