我正在尝试使用不同的类加载器来加载特定的类,并查看该类中的静态变量是否可以具有不同的实例。
基本上,我正在尝试编写Stephen C在this answer中提到的代码。
以下是我的课程:
CustomClassLoader.java
class CustomClassLoader extends ClassLoader
{
public Class loadClass(String classname) throws ClassNotFoundException {
return super.loadClass(classname, true);
}
}
Test.java(包含驱动程序)
class Test {
public static void main(String[] args) throws Exception {
CustomClassLoader c1 = new CustomClassLoader();
CustomClassLoader c2 = new CustomClassLoader();
Class m1, m2;
m1 = c1.loadClass("A");
m2 = c2.loadClass("A");
m1.getField("b").set(null, 10);
System.out.println(m1.getField("b").get(null));
System.out.println(m2.getField("b").get(null));
}
}
A.java(包含静态变量)
class A {
public static int b = 5;
}
当我运行Test类时,我得到以下输出:
$ java Test
10
10
我希望输出为10和5.如何让代码创建我的静态变量的两个实例?
注意:我这样做只是为了实验和学习 - 但我有兴趣知道是否有任何真实世界的应用。
答案 0 :(得分:7)
看起来父类加载器正在加载类“A”,而不是你的CustomClassLoader(因为你调用了super.loadClass)。
以下未经测试的修正应允许您使用自己的类加载器定义“A”类(同时将其他所有内容委托给父加载器)。
为可怕的小屋道歉,我假设单个inputStream.read()会读取所有内容!但你可以希望看到我的意思。
public Class loadClass(String classname) throws ClassNotFoundException {
if (classname.equals("A")) {
InputStream is = getResourceAsStream("A.class");
byte[] bodge = new byte[8192]; // Should read until EOF
try {
int len = is.read(bodge);
return defineClass("A", bodge, 0, len);
} catch (IOException e) {
e.printStackTrace();
}
}
return super.loadClass(classname, true);
}
然后你可能会以ClasscastExceptions或类似的东西结束......
答案 1 :(得分:6)
你的问题是new CustomClassLoader()
创建了一个类加载器,它将尝试将加载类委托给系统类加载器 - 对于两个实例来说都是一样的。您的CustomClassLoader
甚至无法自行加载类。尝试使用URLClassLoader
并将null
作为父级传递。
对于真实世界的应用程序:它对于Java Web容器和应用程序服务器至关重要,它允许不同的应用程序彼此完全隔离,即使它们可能使用许多相同的类。
答案 2 :(得分:0)
如果您查看ClassLoader源甚至是javadoc,您会发现默认情况下ClassLoader委托默认系统ClassLoader,实际上它在实例之间共享。
答案 3 :(得分:0)
我有同样的问题(集成测试)并尝试使用@Michael Borgwardt方法。这里有一些示例代码:
URLClassLoader classLoader1 = new URLClassLoader(new URL[]{new URL("file:///path/to/jar/my-classes.jar")}, null);
URLClassLoader classLoader2 = new URLClassLoader(new URL[]{new URL("file:///path/to/jar/my-classes.jar")}, null);
// Load with classLoader1
Class<?> myClass1 = classLoader1.loadClass("MyClass");
Constructor<?> constructor1 = myClass1.getConstructor();
Object instance1 = constructor1.newInstance();
// Load with classLoader2
Class<?> myClass2 = classLoader2.loadClass("MyClass");
Constructor<?> constructor2 = myClass2.getConstructor();
Object instance2 = constructor2.newInstance();
// Load with system classloader
MyClass myClass = new MyClass();
// ...