我知道这通常很愚蠢,但是在阅读这个问题之前不要拍我.我保证我有一个很好的理由需要这样做:)
可以使用反射来修改java中的常规私有字段,但是当尝试为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()由外部库调用,而不是我的代码,所以只是子类化不会解决问题.
如果我不能这样做,我可以想到的唯一的其他解决方案是复制粘贴整个类并修改方法.这不是理想的,因为我必须保持我的叉最新的图书馆的更改.如果有人有更多的可维护性,我可以接受建议.
解决方法
有可能的.我已经用这个来阻止在webapps中卸载类的调皮的threadlocals.您只需要使用反射来删除最终的修饰符,那么可以修改该字段.
这样的事情会做到这一点:
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,所以如果一些代码在运行之前可能不一定正常运行….