我有一个关于类加载概念的问题。如何在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;
}
}
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)现在我使用这两个不同的类加载器加载一个名为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)执行上述代码的结果:
使用自定义类加载器实例加载类加载器::: sun.misc.Launcher$AppClassLoader@11b86e7类加载器::: sun.misc.Launcher$AppClassLoader@11b86e7 true 1641745,1641745
你能解释一下吗?
试试这个
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);
}
}
产量
class Test1
class Test1
false
两个类加载器都在其父类加载器中启动查找(这就是super()
调用的内容)。所以实际上超级类加载器在两种情况下加载它。
你可以试试这个:
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();
确保my.jar
不在你的类路径上。
在这两种情况下,您使用相同的ClassLoader来执行加载。你有两个ClassLoader,但每个只调用super.loadClass(),它委托给同一个父ClassLoader,即AppClassLoader。