2011-05-10 92 views
12

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

基本上,我试图编写代码为斯蒂芬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; 
} 

当我运行测试类,我得到下面的输出:

$ java Test 
10 
10 

我预期的输出为10和5我怎样才能使代码创建我的静态变量的两个实例?

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

回答

7

看起来类“A”由父类加载器加载,而不是您的CustomClassLoader(因为您调用super.loadClass)。

以下未经测试的修订应允许您使用自己的类加载器(将所有其他代码委托给父加载器)定义“A”类。

对于我认为单个inputStream.read()将读取所有内容的可怕bodge的道歉!但你可以希望看到我的意思。

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或类似的东西最终会...

+0

谢谢,保罗。我会尝试加载这些类而不调用'super.loadClass()'。你能推荐任何解释的好资源吗? – AbdullahC 2011-05-10 12:40:05

+0

我已经更新了我上面的答案。除了http://www.javaworld.com/javaworld/jw-10-1996/jw-10-indepth.html,恐怕我不知道任何好的教程。 – 2011-05-10 12:55:20

+0

你的代码编译完美,但我得到以下例外的线,要么设置或获得'b':'在线程中的异常“主要”java.lang.IllegalAccessException:类测试不能访问类A的成员与修饰符“公共静态“'。 – AbdullahC 2011-05-11 03:48:33

6

您的问题是new CustomClassLoader()创建一个类加载器将尝试加载类委托给系统类加载器 - 这将是两个实例都是相同的。您的CustomClassLoader也无法自行加载类。尝试使用URLClassLoader并将null作为父项。

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

+0

感谢您对真实世界应用程序的额外评论。 – AbdullahC 2011-05-11 04:24:42

0

如果你看一下ClassLoader的源代码或者甚至是javadoc,你会发现默认情况下,ClassLoader委托给默认的系统ClassLoader,实际上它是在实例之间共享的。

+0

嗯......除非你在没有父装载器的情况下使用像URLClassLoader这样的类加载器。我在jvms中创建独立的运行时环境(主要用于测试)。 – Ajax 2016-06-30 02:01:55

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

// ...