3、但是JVM在搜索类的时候,又是如何判定两个class是相同的呢?
  JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。比如网络上的一个Java类org.classloader.simple.NetClassLoaderSimple,javac编译之后生成字节码文件NetClassLoaderSimple.class,ClassLoaderA和ClassLoaderB这两个类加载器并读取了NetClassLoaderSimple.class文件,并分别定义出了java.lang.Class实例来表示这个类,对于JVM来说,它们是两个不同的实例对象,但它们确实是同一份字节码文件,如果试图将这个Class实例生成具体的对象进行转换时,会抛运行时异常java.lang.ClassCaseException,提示这是两个不同的类型。现在通过实例来验证上述所描述的是否正确:
  1)、在web服务器上建一个org.classloader.simple.NetClassLoaderSimple.java类
  package org.classloader.simple;
  public class NetClassLoaderSimple{
  private NetClassLoaderSimple instance;
  public void setNetClassLoaderSimple(Object obj){
  this.instance=(NetClassLoaderSimple)obj;
  }
  }
  org.classloader.simple.NetClassLoaderSimple类的setNetClassLoaderSimple方法接收一个Object类型参数,并将它强制转换成org.classloader.simple.NetClassLoaderSimple类型。
  2)、测试两个class是否相同(NetWorkClassLoader.java)
  package classloader;
  public class NewworkClassLoaderTest{
  public static void main(String[]args){
  try{
  //测试加载网络中的class文件
  String rootUrl="http://localhost:8080/httpweb/classes";
  String className="org.classloader.simple.NetClassLoaderSimple";
  NetworkClassLoader ncl1=new NetworkClassLoader(rootUrl);
  NetworkClassLoader ncl2=new NetworkClassLoader(rootUrl);
  Class<?>clazz1=ncl1.loadClass(className);
  Class<?>clazz2=ncl2.loadClass(className);
  Object obj1=clazz1.newInstance();
  Object obj2=clazz2.newInstance();
  clazz1.getMethod("setNetClassLoaderSimple",Object.class).invoke(obj1,obj2);
  }catch(Exception e){
  e.printStackTrace();
  }
  }
  }
  首先获得网络上一个class文件的二进制名称,然后通过自定义的类加载器NetworkClassLoader创建两个实例,并根据网络地址分别加载这份class,并得到这两个ClassLoader实例加载后生成的Class实例clazz1和clazz2,后将这两个Class实例分别生成具体的实例对象obj1和obj2,再通过反射调用clazz1中的setNetClassLoaderSimple方法。
  3)、查看测试结果

  结论:从结果中可以看出,虽然是同一份class字节码文件,但是由于被两个不同的ClassLoader实例所加载,所以JVM认为它们是两个不同的类。
  4、ClassLoader的体系架构:

  验证ClassLoader加载类的原理:
  测试1:打印ClassLoader类的层次结构,请看下面这段代码:
  ClassLoader loader=ClassLoaderTest.class.getClassLoader();//获得加载ClassLoaderTest.class这个类的类加载器
  while(loader!=null){
  System.out.println(loader);
  loader=loader.getParent();//获得父类加载器的引用
  }
  System.out.println(loader);
  打印结果:

  第一行结果说明:ClassLoaderTest的类加载器是AppClassLoader。
  第二行结果说明:AppClassLoader的类加器是ExtClassLoader,即parent=ExtClassLoader。
  第三行结果说明:ExtClassLoader的类加器是Bootstrap ClassLoader,因为Bootstrap ClassLoader不是一个普通的Java类,所以ExtClassLoader的parent=null,所以第三行的打印结果为null是这个原因。