【发布时间】:2014-11-27 15:27:34
【问题描述】:
我有一个静态类 (Foo) 和一个主类 (Main)
参见 Main.java:
public class Main {
public static void main(String[] args) {
System.out.println(Foo.i); // 0
Foo.i++;
System.out.println(Foo.i); // 1
// restart Foo here
System.out.println(Foo.i); // 1 again...I need 0
}
}
参见 Foo.java:
public class Foo {
public static int i = 0;
}
有没有办法重新启动或重置静态类?
注意:我需要这个,因为我正在使用 jUnit 测试一个静态类,并且我需要在第二次测试之前清理参数。
编辑
几乎可以解决:
使用 StanMax 答案,我可以这样做:
Main.java
public class Main {
public static void main(String[] args) throws Exception {
test();
test();
}
public static void test() throws Exception {
System.out.println("\ntest()");
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> fooClass = myClassLoader.loadClass(Foo.class.getCanonicalName());
Object foo = fooClass.newInstance();
System.out.println("Checking classloader: " + foo.getClass().getClassLoader());
System.out.println("GC called!");
System.gc();
}
}
MyClassLoader.java
public class MyClassLoader {
private URLClassLoader urlClassLoader;
public MyClassLoader() {
try {
URL url = new File(System.getProperty("user.dir") + "/bin/").toURL();
URL[] urlArray = {url};
urlClassLoader = new URLClassLoader(urlArray, null);
} catch (Exception e) {
}
}
public Class<?> loadClass(String name) {
try {
return (Class<?>) urlClassLoader.loadClass(name);
} catch (Exception e) {
}
return null;
}
@Override
protected void finalize() throws Throwable {
System.out.println("MyClassLoader - End.");
}
}
Foo.java
public class Foo {
public static int i = 0;
static {
System.out.println("Foo - BEGIN ---------------------------------");
}
public void finalize() throws Throwable {
System.out.println("Foo - End.");
}
}
输出
test()
Foo - BEGIN ---------------------------------
Checking classloader: java.net.URLClassLoader@ec160c9
GC called!
MyClassLoader - End.
Foo - End.
test()
Foo - BEGIN ---------------------------------
Checking classloader: java.net.URLClassLoader@ec3fb9b
GC called!
MyClassLoader - End.
Foo - End.
问题:如果我做下面的演员:
Foo foo = (Foo) fooClass.newInstance();
我得到错误:
java.lang.ClassCastException
【问题讨论】:
-
对于这个特定的示例,只需在您的
Main方法中执行Foo.i = 0;。 -
您有 ClassCastException,因为 URLClassLoader 加载的 Foo 类与运行代码的 ClassLoader 加载的 Foo 类不同(它们不是 ==)。即使它们具有完全相同的定义,您也不能将一个转换为另一个。这种技巧起作用的唯一方法是,如果 Foo 实现了由两个类加载器共享的 ClassLoader 加载的接口 FooInterface,在这种情况下,您可以强制转换为 FooInterface。但这并不能帮助您访问静态字段。
-
NamshubWriter:好的,我做到了....但主要问题是因为我使用的是动态类型....我得到“fooClass 无法解析为类型”。也许Refletion API中的某些东西可以提供帮助......
-
@Adrian 有正确的答案。不要做任何这些。如有必要,在您的测试和静态类之间创建一个新接口。接口的默认实现将提供静态类的字段。对于测试,您可以使用 EasyMock 或只创建此接口的新实例以返回您想要的值。不要乱用类加载器或垃圾收集器。
-
相关:这似乎并不能解决我在如何正确运行 Java 中的微基准测试时遇到的问题(或确实解决了问题)。该解决方案强制类加载器在每次运行时都运行(这是 java 基准测试的全部问题)。我希望重置所有静态变量,包括所有单例等,以便我的整个程序可以有效地运行两次;第二次运行将是所有东西都满载,并且是板凳。