类加载器的分类

分类

无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有三个,如下所示:

image-20210730200638388

  • 启动类加载器

    • 负责加载JAVA_HOME/lib目录下的可以被虚拟机识别(通过文件名称,比如rt.jar``tools.jar)的字节码文件。
    • 与之对应的是java.lang.ClassLoader
  • 扩展类加载器

    • 负责加载JAVA_HOME/lib/ext目录下的的字节码文件。
    • 对应sun.misc.Launcher类 此类继承于启动类加载器ClassLoader
  • 应用程序类加载器

    • 负责加载ClassPath路径下的字节码 也就是用户自己写的类。
    • 对应于sun.misc.Launcher.AppClassLoader类 此类继承于扩展类加载器Launcher
  • 用户自定义加载器

    • 需要继承系统类加载器ClassLoader,并重写findClass方法。

    • 负责加载指定位置的字节码文件。通过类中的path变量指定。

    • 如下为用户重写的自定义加载器

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      package cn.shaoxiongdu;

      import java.io.ByteArrayOutputStream;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.IOException;
      import java.io.InputStream;

      /**
      * @作者: 写Bug的小杜 【email@shaoxiongdu.cn】
      * @时间: 2021/07/30
      * @描述: 用户自定义类加载器
      */
      public class MyClassLoader extends ClassLoader {

      private String path="/home/lib/"; //默认加载路径

      private String name; //类加载器名称

      private final String filetype=".class"; //文件类型


      public MyClassLoader(String name) {
      // TODO Auto-generated constructor stub
      super();
      this.name=name;
      }

      public MyClassLoader(ClassLoader parent,String name){
      super(parent);
      this.name=name;
      }

      @Override
      public Class<?> findClass(String name) throws ClassNotFoundException {
      // TODO Auto-generated method stub
      byte[] b=loadClassData(name);
      return defineClass(name, b, 0, b.length);
      }

      private byte[] loadClassData(String name) {
      byte[] data=null;
      InputStream in=null;
      name=name.replace('.', '/');
      ByteArrayOutputStream out=new ByteArrayOutputStream();
      try {
      in=new FileInputStream(new File(path+name+filetype));
      int len=0;
      while(-1!=(len=in.read())){
      out.write(len);
      }
      data=out.toByteArray();
      } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }finally{
      try {
      in.close();
      out.close();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }
      return data;
      }

      public String getPath() {
      return path;
      }

      public void setPath(String path) {
      this.path = path;
      }

      @Override
      public String toString() {
      // TODO Auto-generated method stub
      return this.name;
      }

      }