java 使用不同的加载器在 JVM 中加载一个类两次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14257357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:38:36  来源:igfitidea点击:

Loading a class twice in JVM using different loaders

javaclassloader

提问by Hitesh

I have one question regarding concepts of class loading. How to load a .class file twice in JVM. I am also writing an excerpt of code that I have written to accomplish this..

我有一个关于类加载概念的问题。如何在 JVM 中两次加载 .class 文件。我也在写一段我为完成这个而写的代码的摘录。

1) Loader 1 code

1) 加载器 1 代码

public class MyClassLoader extends ClassLoader {

    public MyClassLoader(){
        super(MyClassLoader.class.getClassLoader());
    }

    public Class loadClass(String classname){
        try {
            return super.loadClass(classname);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

2) Loader 2 code

2) 加载器 2 代码

public class AnotherClassLoader extends ClassLoader {

    public AnotherClassLoader(){
        super(AnotherClassLoader.class.getClassLoader());
    }

    public Class loadClass(String classname){
        try {
            return super.loadClass(classname);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

3) Now i am loading a class named A using this two different class loaders. I suppose the operation classA1==newClassA should return false. Here is the code:

3) 现在我正在使用这两个不同的类加载器加载一个名为 A 的类。我想操作 classA1==newClassA 应该返回 false。这是代码:

public static void main(String[] args) {
        MyClassLoader loader1 = new MyClassLoader();
        AnotherClassLoader newLoader = new AnotherClassLoader();
            System.out.println("Load with Custom Class Loader instance");
            Class classA1 = loader1.loadClass("com.hitesh.coreJava.A");
            System.out.println("Class Loader:::"+classA1.getClassLoader());
            Class newClassA = newLoader.loadClass("com.hitesh.coreJava.A");
            System.out.println("Class Loader:::"+newClassA.getClassLoader());
            System.out.println(classA1==newClassA);
            System.out.println(classA1.hashCode() + " , " + newClassA.hashCode());

    }

4) Result of executing above code:

4)执行上述代码的结果:

Load with Custom Class Loader instance Class Loader:::sun.misc.Launcher$AppClassLoader@11b86e7 Class Loader:::sun.misc.Launcher$AppClassLoader@11b86e7 true 1641745 , 1641745

使用自定义类加载器实例加载类加载器:::sun.misc.Launcher$AppClassLoader@11b86e7 类加载器:::sun.misc.Launcher$AppClassLoader@11b86e7 true 1641745 , 1641745

Could you please explain this

你能解释一下吗

回答by Evgeniy Dorofeev

Try this

试试这个

public class Test1 {

    static class TestClassLoader1 extends ClassLoader {

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (!name.equals("Test1")) {
                return super.loadClass(name);
            }
            try {
                InputStream in = ClassLoader.getSystemResourceAsStream("Test1.class");
                byte[] a = new byte[10000];
                int len  = in.read(a);
                in.close();
                return defineClass(name, a, 0, len);
            } catch (IOException e) {
                throw new ClassNotFoundException();
            }
        }
    }


    public static void main(String[] args) throws Exception {
        Class<?> c1 = new TestClassLoader1().loadClass("Test1");
        Class<?> c2 = new TestClassLoader1().loadClass("Test1");
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c1 == c2);
    }
}

output

输出

class Test1
class Test1
false

回答by gaborsch

Both classloaders start the lookup in their parent classloader (that's what the super()call is about). So actually the super classloader loads it in both cases.

两个类加载器都在其父类加载器中开始查找(这就是super()调用的内容)。所以实际上超级类加载器在这两种情况下都会加载它。

You can try this:

你可以试试这个:

String pathToJar = "C:\path\to\my.jar";
String className = "com.mypackage.ClassA";
URLClassLoader cl1 = new URLClassLoader(new URL[] { new URL(pathToJar) });
URLClassLoader cl2 = new URLClassLoader(new URL[] { new URL(pathToJar) });
Class<?> c1 = cl1.loadClass(className);
Class<?> c2 = cl2.loadClass(className);
System.out.println(c1);
System.out.println(c2);
System.out.println(c1==c2);
cl1.close();
cl2.close();

Make sure that my.jaris NOT on your classpath.

确保它my.jar不在您的类路径中。

回答by Peter Lawrey

In both cases you are using the same ClassLoader to perform the loading. You have two ClassLoaders but each just call super.loadClass() which delegates to the same parent ClassLoader which is AppClassLoader.

在这两种情况下,您都使用相同的 ClassLoader 来执行加载。您有两个 ClassLoader,但每个都只调用 super.loadClass(),它委托给同一个父类加载器,即 AppClassLoader。