类加载器双亲委托机制

2019-12-30  本文已影响0人  龙剑灵

自定义类加载器 MyTest18

public class MyTest18 extends ClassLoader{

  private String classLoaderName;

  private String path;

  private String feleExtension = ".class";

  public MyTest18(String classLoaderName) {
    super(); //将系统类加载器当做该类加载的父加载器
    this.classLoaderName = classLoaderName;
  }

  public MyTest18(ClassLoader parent, String classLoaderName) {
    super(parent);// 显示指定该类加载器父加载器
    this.classLoaderName = classLoaderName;
  }
  public void setPath(String path) {
    this.path = path;
  }

  @Override
  protected Class<?> findClass(String className) throws ClassNotFoundException {
    System.out.println("className: " + className);
    System.out.println("classLoaderName: " + this.classLoaderName);

    byte[] data = this.loadClassData(className);
    return this.defineClass(className, data, 0, data.length);
  }

  private byte[] loadClassData(String className){
    byte[] data = null;
    InputStream is = null;
    ByteArrayOutputStream baos = null;

    System.out.println("loadClassData.222.........");
    try {
      className = className.replace(".", "\\");
      String fileName = this.path + className + this.feleExtension;
      System.out.println("fileName: " + fileName);
      is = new FileInputStream(new File(fileName));
      baos = new ByteArrayOutputStream();
      int ch = 0;
      while (-1 != (ch = is.read())) {
        baos.write(ch);
      }
      data = baos.toByteArray();
    } catch (Exception e) {

    }finally {
      try {
        is.close();
        baos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return data;
  }
public static void main(String[] args) throws Exception {

    MyTest17 myTest = new MyTest17("loader17");
    //myTest.setPath("E:\\gitSpace\\jdk8\\out\\production\\classes\\");
    myTest.setPath("c:\\");

    Class<?> clazz = myTest.loadClass("jvm.classloader.MyTest2");
    System.out.println("class: " + clazz);
    System.out.println("class.hashCode: " + clazz.hashCode());
    Object object = clazz.newInstance();
    System.out.println(object);
    System.out.println("--------------------------------");

    MyTest17 myTest2 = new MyTest17("loader177");
    //myTest.setPath("E:\\gitSpace\\jdk8\\out\\production\\classes\\");
    myTest2.setPath("c:\\");

    Class<?> clazz2 = myTest2.loadClass("jvm.classloader.MyTest2");
    System.out.println("class2: " + clazz2);
    System.out.println("class2.hashCode: " + clazz2.hashCode());
    Object object2 = clazz2.newInstance();
    System.out.println(object2);
  }
本例中,2个类加载器,都委托系统(或应用)加载器去加载,因此重写的findClass不会执行,没输出,在类路径上能找到,只会执行一次加载, hashCode是一致的

class: class jvm.classloader.MyTest2
class.hashCode: 366712642
jvm.classloader.MyTest2@6d06d69c


class2: class jvm.classloader.MyTest2
class2.hashCode: 366712642
jvm.classloader.MyTest2@7852e922

若将类路径下的MyTest2.class删除后则输出如下
每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成

className: jvm.classloader.MyTest2
classLoaderName: loader17
loadClassData..........
fileName: c:\jvm\classloader\MyTest2.class
class: class jvm.classloader.MyTest2
class.hashCode: 135721597
jvm.classloader.MyTest2@87aac27


className: jvm.classloader.MyTest2
classLoaderName: loader177
loadClassData..........
fileName: c:\jvm\classloader\MyTest2.class
class2: class jvm.classloader.MyTest2
class2.hashCode: 1406718218
jvm.classloader.MyTest2@e9e54c2

public static void main(String[] args) throws Exception {

    MyTest18 myTest = new MyTest18("loader18");
    //myTest.setPath("E:\\gitSpace\\jdk8\\out\\production\\classes\\");
    myTest.setPath("c:\\");

    Class<?> clazz = myTest.loadClass("jvm.classloader.MyTest2");
    System.out.println("class: " + clazz);
    System.out.println("class.hashCode: " + clazz.hashCode());
    Object object = clazz.newInstance();
    System.out.println(object);
    System.out.println("--------------------------------");

    MyTest18 myTest2 = new MyTest18(myTest, "loader18");
    //myTest.setPath("E:\\gitSpace\\jdk8\\out\\production\\classes\\");
    myTest2.setPath("c:\\");

    Class<?> clazz2 = myTest2.loadClass("jvm.classloader.MyTest2");
    System.out.println("class2: " + clazz2);
    System.out.println("class2.hashCode: " + clazz2.hashCode());
    Object object2 = clazz2.newInstance();
    System.out.println(object2);

    System.out.println("--------------------------------");

    MyTest18 myTest3 = new MyTest18(myTest2, "loader19");
    //myTest.setPath("E:\\gitSpace\\jdk8\\out\\production\\classes\\");
    myTest3.setPath("c:\\");

    Class<?> clazz3 = myTest3.loadClass("jvm.classloader.MyTest2");
    System.out.println("class3: " + clazz3);
    System.out.println("class3.hashCode: " + clazz3.hashCode());
    Object object3 = clazz3.newInstance();
    System.out.println(object3);
  }
此示例没删除MyTest2.class则输出如下
第2个加载器加载的是父类的,第3个加载时,在1中已经加载过,所以3者是加载的同个类

className: jvm.classloader.MyTest2
classLoaderName: loader18
loadClassData.222.........
fileName: c:\jvm\classloader\MyTest2.class
class: class jvm.classloader.MyTest2
class.hashCode: 135721597
jvm.classloader.MyTest2@87aac27


class2: class jvm.classloader.MyTest2
class2.hashCode: 135721597
jvm.classloader.MyTest2@3e3abc88


class3: class jvm.classloader.MyTest2
class3.hashCode: 135721597
jvm.classloader.MyTest2@6ce253f1

上一篇下一篇

猜你喜欢

热点阅读