我知道这通常很愚蠢,但在阅读问题之前不要开枪。我保证我有充分的理由需要这样做:)
可以使用反射修改 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/