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

Hit*_*esh 5 java classloader

我有一个关于类加载概念的问题.如何在JVM中加载.class文件两次.我也在编写一段代码,我已经写完了这个代码.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

}

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

}

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

    }
Run Code Online (Sandbox Code Playgroud)

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

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

你能解释一下吗?

gab*_*sch 6

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.

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 ? "Parent classloader loads" : "Parent classloader does not load");
cl1.close();
cl2.close();
Run Code Online (Sandbox Code Playgroud)

Make sure that my.jar is NOT on your classpath.


Evg*_*eev 6

试试这个

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

产量

class Test1
class Test1
false
Run Code Online (Sandbox Code Playgroud)

  • 上面的代码片段是正确的.确实,加载到JVM中的任何类都由(package,className,Class Loader Name)标识.因此,可以通过使用两个不同的类加载器实例在JVM中加载一个类两次.为此,您需要在Custom Class Loader代码中显式调用defineClass(),因为此方法在运行时检查两个不同的实例是否正在加载类. (2认同)

Pet*_*rey 3

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