当前位置: 首页 > 面试题库 >

使用反射更改静态最终File.separatorChar进行单元测试?

左仰岳
2023-03-14
问题内容

具体来说,我正在尝试为需要用于File.separatorChar在Windows和Unix上构建路径的方法创建单元测试。该代码必须在两个平台上都可以运行,但是当我尝试更改此static
final字段时,却遇到了JUnit错误。

任何人都知道发生了什么事吗?

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

如果基础字段是final,则该方法将为该字段成功地抛出IllegalAccessException除非setAccessible(true)
并且该字段是非静态的

因此,在第一看来,你的运气了,因为File.separatorCharstatic。令人惊讶的
一种方法来解决这个问题:简单地让static现场不再final通过反射

我从javaspecialistist.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);
}

我已经对其进行了测试,并且可以正常工作:

setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"

使用这种技术时要格外小心 。除了毁灭性的后果,以下内容确实有效:

setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"

重要更新 :上述解决方案 并非
在所有情况下都适用。如果使该字段可访问并且在重置前通读了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


 类似资料:
  • 问题内容: 我有一堂课,但不幸的是,我需要在运行时更改它。 使用反射我得到这个错误: 有什么办法可以改变价值? 问题答案: 假设没有阻止你执行此操作,则可以使用来绕开并重置修饰符以摆脱,并实际上修改字段。 这是一个例子: 假设没有SecurityException抛出,上面的代码将打印出来”Everything is true”。 实际执行的操作如下: 基本boolean值true和falsein

  • 使用Java反射更改私有静态final字段 我按照上面链接中的说明使用java反射更改私有静态final字段。我有一个名为“数据”的对象在“data”内部,有一个名为“type”的私有静态最终变量我想将“type”设置为null。这是我的密码。 我试着在Java1.7上用类似的代码来做这件事,结果成功了。但是在Android上运行此代码会产生以下错误:java。lang.NoSuchFieldEx

  • 问题内容: 我有一个带有静态变量的Java类 如何使用反射访问对象? (我有字符串。我需要访问该对象。) 问题答案: 访问静态字段的方式与普通字段完全相同,只是不需要将任何参数传递给方法(可以传递null)。 试试这个:

  • 问题内容: 基于使用Java反射更改私有静态最终字段,我尝试设置私有静态最终字段。 (我知道这非常骇人,但是这个问题与代码质量无关;与Java反射有关。) 此打印 我已经使用OpenJDK 6和7,以及Oracle 7进行了尝试。 我不知道Java反射可以提供什么保证。但是,如果失败了,我以为会有一个(实际上所有反射方法都会抛出异常)。 这是怎么回事 问题答案: Java内联字段可在编译时初始化为

  • 问题内容: 请参考下面的代码。运行代码时,我可以更改最终非静态变量的值。但是,如果我尝试更改最终静态变量的值,则会抛出异常。 我的问题是,为什么在非静态最终变量也不会抛出异常,反之亦然。为什么会有所不同? 问题答案: 该解决方案并非没有缺点,它可能无法在所有情况下都有效: 如果在字段声明中将字段初始化为编译时常量,则对该字段的更改可能不可见,因为该最终字段的使用会在编译时用编译时常量替换。 另一个

  • 我有两个UnitTest项目为我的Android项目。一个用于JUnit测试,一个用于Android Unit测试。在JUnit测试项目中,我创建了一个类来访问或设置私有字段、方法或构造函数。(附言:对于那些对完整代码感到好奇的人,请告诉我,我会把它添加到这篇文章的底部。) 我也有UnitTets来测试这些私有方法的访问。现在,所有这些UnitTest都可以工作,接受一个:设置final stat