Java 静态变量的多个实例

Java 静态变量的多个实例,java,reflection,static,classloader,Java,Reflection,Static,Classloader,我正在尝试使用不同的类加载器来加载一个特定的类,看看该类中的静态变量是否可以有不同的实例 基本上,我正试图为Stephen C在文章中提到的内容编写代码 以下是我的课程: CustomClassLoader.java class CustomClassLoader extends ClassLoader { public Class loadClass(String classname) throws ClassNotFoundException { return su

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

基本上,我正试图为Stephen C在文章中提到的内容编写代码

以下是我的课程:

CustomClassLoader.java

class CustomClassLoader extends ClassLoader
{
    public Class loadClass(String classname)  throws ClassNotFoundException {
        return super.loadClass(classname, true);
    }
}
java(其中包含驱动程序)

A.java(包含静态变量)

当我运行测试类时,我得到以下输出:

$ java Test
10
10
我期望输出为10和5。如何让代码创建静态变量的两个实例


注意:我这样做只是为了实验和学习——但我很想知道是否有任何实际应用程序可以使用它。

看起来类“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);
}

然后,您可能会遇到ClassCastException或类似的问题…

您的问题是
新建CustomClassLoader()
创建一个类加载器,该类加载器将尝试将加载类委托给系统类加载器-这两个实例都是相同的。您的
CustomClassLoader
甚至无法加载类本身。尝试使用
URLClassLoader
并将
null
作为父级传递


对于真实世界的应用程序:允许不同的应用程序彼此完全隔离,这对于Java Web容器和应用程序服务器来说是至关重要的,即使它们可能使用许多相同的类。

如果查看ClassLoader源代码甚至javadocs,您会发现默认情况下ClassLoader将委托给默认类系统类加载器,它实际上是在实例之间共享的。

我也遇到了同样的问题(集成测试),并使用@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();

// ...
URLClassLoader classLoader1=newurlclassloader(newurl[]{newurl(“file:///path/to/jar/my-classes.jar“},空);
URLClassLoader classLoader2=新URLClassLoader(新URL[]{新URL(“file:///path/to/jar/my-classes.jar“},空);
//使用classLoader1加载
类myClass1=classLoader1.loadClass(“MyClass”);
构造函数constructor1=myClass1.getConstructor();
Object instance1=constructor1.newInstance();
//使用classLoader2加载
类myClass2=classLoader2.loadClass(“MyClass”);
构造函数constructor2=myClass2.getConstructor();
Object instance2=constructor2.newInstance();
//使用系统类加载器加载
MyClass MyClass=新的MyClass();
// ...

谢谢你,保罗。我将尝试加载这些类,而不调用
super.loadClass()
。你能推荐一些好的资源来解释这一点吗?我已经更新了上面的答案。恐怕我只知道。你的代码编译得很好,但我在设置或获取
b
的行中遇到以下异常:
线程“main”java.lang.IllegalAccessException中的异常:类测试无法访问带有修饰符“public static”的类a的成员。谢谢,当我将class
A
公开时,它工作并为静态变量输出了不同的值。感谢您对实际应用程序的附加评论。嗯。。。除非您使用像URLClassLoader这样的类加载器,而不使用父加载器。我经常这样做是为了在JVM中创建隔离的运行时环境(主要用于测试)。
    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);
}
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();

// ...