They are same class : true
两个Object用==比较,返回true,就是两者的地址相等,就说明是同一个Object。因此我们能看出,同名的class在JVM只会加载一次,所以两者相等。
但是如果用URLClassLoader加载外面的类Ext4Test,效果却不一样:
String url = "file:/" + System.getProperty("user.dir") +"/newClass/";
URLClassLoader ucl1 = new URLClassLoader(new URL[]{new URL(url)});
URLClassLoader ucl2 = new URLClassLoader(new URL[]{new URL(url)});
Class
c1 = ucl1.loadClass("com.jscai.classloader.Ext4Test");
Class
c2 = ucl2.loadClass("com.jscai.classloader.Ext4Test");
System.out.println("They aresame class : " + (c1 == c2));
console:
They are same class : false
虽然类名是一样的,但是使用的类加载器实例不同,所以JVM不认为这俩是同一个class,两者就不想等了。而上个例子中,两个Inner4Test的class相等,是因为JVM的类加载实例都是单例,同名和同加载器实例的两个条件都符合了。
同样我们可以把类加载器实例换成一样的,两个class就相等了:
URLClassLoader ucl1 = new URLClassLoader(new URL[]{new URL(url)});
Class
c1 = ucl1.loadClass("com.jscai.classloader.Ext4Test");
Class
c2 = ucl1.loadClass("com.jscai.classloader.Ext4Test");
System.out.println("They aresame class : " + (c1 == c2));
console:
They are same class : true
因此,根据这个特点,我们可以自定义类加载器,来实现动态加载类(装载):一方面管理好现有的实例对象,另一方面监听是否有jar更新,如果有更新就重新生成加载器实例去加载这些class,这样新的class就能代替旧的class,就能实现动态加载而避免整体重启了。例如Tomcat的热部署。 (当然,具体实现还是很复杂的,没有我说的那么简单!)
---- 源码参考JDK-7