Ste*_*all 26 java reflection file-io unit-testing
具体来说,我正在尝试为一个方法创建单元测试,该方法需要用于File.separatorChar
在windows和unix上构建路径.代码必须在两个平台上运行,但当我尝试更改此静态最终字段时,我会收到JUnit错误.
任何人都知道发生了什么事吗?
Field field = java.io.File.class.getDeclaredField( "separatorChar" );
field.setAccessible(true);
field.setChar(java.io.File.class,'/');
Run Code Online (Sandbox Code Playgroud)
当我这样做时,我明白了
IllegalAccessException: Can not set static final char field java.io.File.separatorChar to java.lang.Character
Run Code Online (Sandbox Code Playgroud)
思考?
pol*_*nts 65
从以下文档Field.set
:
如果底层字段是final,则该方法抛出一个
IllegalAccessException
除非setAccessible(true)
该字段成功且该字段是非静态的.
所以起初似乎你运气不好,因为File.separatorChar
是static
.令人惊讶的是一种方法来解决这个问题:简单地让static
现场不再final
通过反射.
我从javaspecialist.eu改编了这个解决方案:
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
// remove final modifier from field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
Run Code Online (Sandbox Code Playgroud)
我测试了它,它的工作原理:
setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"
Run Code Online (Sandbox Code Playgroud)
用这种技术做极其谨慎.抛开毁灭性后果,以下实际上有效:
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
Run Code Online (Sandbox Code Playgroud)
重要更新:上述解决方案并非在所有情况下都有效.如果该字段在重置之前可以访问并通过Reflection读取,IllegalAccessException
则抛出该字段.它失败是因为Reflection API创建了FieldAccessor
缓存和重用的内部对象(请参阅java.lang.reflect.Field#acquireFieldAccessor(boolean)实现).示例测试代码失败:
Field f = File.class.getField("separatorChar"); f.setAccessible(true); f.get(null);
// call setFinalStatic as before: throws IllegalAccessException
Run Code Online (Sandbox Code Playgroud)