问题描述
具体来说,我正在尝试为需要使用 File.separatorChar
在 windows 和 unix 上构建路径的方法创建单元测试.代码必须在两个平台上都运行,但是当我尝试更改此静态最终字段时,JUnit 出现错误.
Specifically, I'm trying to create a unit test for a method which requires uses File.separatorChar
to build paths on windows and unix. The code must run on both platforms, and yet I get errors with JUnit when I attempt to change this static final field.
有人知道发生了什么吗?
Anyone have any idea what's going on?
Field field = java.io.File.class.getDeclaredField( "separatorChar" );
field.setAccessible(true);
field.setChar(java.io.File.class,'/');
当我这样做时,我得到
IllegalAccessException: Can not set static final char field java.io.File.separatorChar to java.lang.Character
想法?
推荐答案
来自 Field.set
:
如果基础字段是最终字段,则该方法将抛出 IllegalAccessException
除非 setAccessible(true)
已针对该字段成功并且该字段是非静态的.
If the underlying field is final, the method throws an
IllegalAccessException
unlesssetAccessible(true)
has succeeded for this field and this field is non-static.
所以一开始你似乎不太走运,因为File.separatorChar
是static
.令人惊讶的是, 有一种方法可以解决这个问题:只需通过反射使 static
字段不再是 final
.
So at first it seems that you are out of luck, since File.separatorChar
is static
. Surprisingly, there is a way to get around this: simply make the static
field no longer final
through reflection.
我改编了这个解决方案 来自 javaspecialist.eu:
I adapted this solution from 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);
}
我已经对其进行了测试并且可以正常工作:
I've tested it and it works:
setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"
<小时>
请务必谨慎使用此技术.撇开毁灭性的后果不谈,以下方法确实有效:
Do exercise extreme caution with this technique. Devastating consequences aside, the following actually works:
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
<小时>
重要更新:上述解决方案并非在所有情况下都有效.如果该字段在重置之前可访问并通过反射读取,则会引发 IllegalAccessException
.它失败是因为反射 API 创建了内部 FieldAccessor
对象,这些对象被缓存和重用(参见 java.lang.reflect.Field#acquireFieldAccessor(boolean) 实现).失败的示例测试代码:
Important update: the above solution does not work in all cases. If the field is made accessible and read through Reflection before it gets reset, an IllegalAccessException
is thrown. It fails because the Reflection API creates internal FieldAccessor
objects which are cached and reused (see the java.lang.reflect.Field#acquireFieldAccessor(boolean) implementation).
Example test code which fails:
Field f = File.class.getField("separatorChar"); f.setAccessible(true); f.get(null);
// call setFinalStatic as before: throws IllegalAccessException
这篇关于使用反射更改静态最终 File.separatorChar 进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2