我知道这通常很愚蠢,但是在阅读这个问题之前不要拍我.我保证我有一个很好的理由需要这样做:)
可以使用反射来修改java中的常规私有字段,但是当尝试为final字段执行相同操作时,Java会引发安全异常.@H_502_3@
我会认为这是严格执行的,但是想到我会问,无论如何,以防万一有人想出了一个黑客这样做.@H_502_3@
让我们说我有一个外部库与类“SomeClass”@H_502_3@
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的值,所以它返回我的版本的类与修改的方法.@H_502_3@
本质上,我只想用安全检查包裹呼叫,然后调用原始方法.@H_502_3@
外部库总是使用getInstance()来获取这个类的一个实例(即它是一个单例).@H_502_3@
编辑:只是为了澄清,getInstance()由外部库调用,而不是我的代码,所以只是子类化不会解决问题.@H_502_3@
如果我不能这样做,我可以想到的唯一的其他解决方案是复制粘贴整个类并修改方法.这不是理想的,因为我必须保持我的叉最新的图书馆的更改.如果有人有更多的可维护性,我可以接受建议.@H_502_3@
解决方法
有可能的.我已经用这个来阻止在webapps中卸载类的调皮的threadlocals.您只需要使用反射来删除最终的修饰符,那么可以修改该字段.
这样的事情会做到这一点:@H_502_3@
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); }