多个静态变量实例

时间:2011-05-10 12:29:52

标签: java reflection static classloader

我正在尝试使用不同的类加载器来加载特定的类,并查看该类中的静态变量是否可以具有不同的实例。

基本上,我正在尝试编写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.如何让代码创建我的静态变量的两个实例?

注意:我这样做只是为了实验和学习 - 但我有兴趣知道是否有任何真实世界的应用。

4 个答案:

答案 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();

// ...