手写一个类加载器demo

Posted shenwen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写一个类加载器demo相关的知识,希望对你有一定的参考价值。

1、什么是类加载器?

技术图片

 

 

 2、加载方式

ClassLoader类加载器,主要的作用是将class文件加载到jvm虚拟机中。jvm启动的时候,并不是一次性加载所有的类,而是根据需要动态去加载类,主要分为隐式加载和显示加载。

隐式加载:程序代码中不通过调用ClassLoader来加载需要的类,而是通过JVM类自动加载需要的类到内存中。例如,当我们在类中继承或者引用某个类的时候,

JVM在解析当前这个类的时,发现引用的类不在内存中,那么就会自动将这些类加载到内存中。

显示加载:代码中通过Class.forName(),this.getClass.getClassLoader.LoadClass(),自定义类加载器中的findClass()方法等。

显示加载的时候,当我们获取到class对象之后,需要调用class对象的new instans()生成实例。

3、类加载器的种类及作用

(1)BootStrap ClassLoader:主要加载%JRE_HOME%\\lib下的rt.jar、resources.jar、charsets.jar和class等。可以通System.getProperty("sun.boot.class.path")

 

(2)Extention ClassLoader:主要加载目录%JRE_HOME%\\lib\\ext目录下的jar包和class文件。也可以通过System.out.println(System.getProperty("java.ext.dirs"))查看加载类文件的路径。

 

(3)AppClassLoader:主要加载当前应用下的classpath路径下的类。之前我们在环境变量中配置的classpath就是指定AppClassLoader的类加载路径。

(4)用户自定义类加载器

4、继承关系技术图片

 

 

 

技术图片

 

 

 

 

5、双亲委派机制

例如:当jvm要加载Test.class的时候,

  (1)首先会到自定义加载器中查找,看是否已经加载过,如果已经加载过,则返回字节码。

  (2)如果自定义加载器没有加载过,则询问上一层加载器(即AppClassLoader)是否已经加载过Test.class。

  (3)如果没有加载过,则询问上一层加载器(ExtClassLoader)是否已经加载过。

  (4)如果没有加载过,则继续询问上一层加载(BoopStrap ClassLoader)是否已经加载过。

  (5)如果BoopStrap ClassLoader依然没有加载过,则到自己指定类加载路径下("sun.boot.class.path")查看是否有Test.class字节码,有则返回,没有通

知下一层加载器ExtClassLoader到自己指定的类加载路径下(java.ext.dirs)查看。

  (6)依次类推,最后到自定义类加载器指定的路径还没有找到Test.class字节码,则抛出异常ClassNotFoundException。如下图:

技术图片

 

 

 7、自定义loaderclass

(1)新建一个java文件,保存在相应的目录。

技术图片

 

 

 技术图片

 

 

 (2)用cmd命令进入到world类的上级目录,运行javac命令,生成.class文件。

技术图片

 

 

 (3)创建自己定义的classload类。

//继承ClassLoader类,重写findclass方法。
public class MyClassloader extends ClassLoader 

  private String path;
  private String classloaderName;

  public MyClassloader(String path,String classloaderName)
    this.path = path;
    this.classloaderName = classloaderName;
  

  //用于寻找类文件
  @Override
  public Class findClass(String name)
    byte[] b =loadClassData(name);
    return defineClass(name,b,0,b.length);
  

  public byte[] loadClassData(String name) 
    name = path + name + ".class";
    InputStream in = null;
    ByteArrayOutputStream out = null;

    try 
      in = new FileInputStream(new File(name));
      out = new ByteArrayOutputStream();
      int i = 0;
      while ((i = in.read()) != -1)
      out.write(i);
      
     catch (Exception e) 
      e.printStackTrace();
    finally 
      try 
        out.close();
        in.close();
       catch (IOException e) 
        e.printStackTrace();
      
    
    return out.toByteArray();
  

(4)创建测试类,测试结果。

public class ClassLoderCheck 

  public static void main(String[] args)
      throws IllegalAccessException, InstantiationException, ClassNotFoundException 
    MyClassloader classloader = new MyClassloader("D:/jvm/", "myclasscloderz");
    Class c = classloader.loadClass("World");
    System.out.println(c.getClassLoader());
    System.out.println(c.getClassLoader().getParent());
    System.out.println(c.getClassLoader().getParent().getParent());
    c.newInstance();
  

运行结果为:

技术图片

 

 自定义类加载器的作用:jvm自带的三个加载器只能加载指定路径下的类字节码。如果某个情况下,我们需要加载应用程序之外的类文件呢?比如本地D盘下的,或者去加载网络上的某个类文件,这种情况就可以使用自定义加载器了。

参考网址:cnblogs.com/gdpuzxs/p/7044963.html

 

以上是关于手写一个类加载器demo的主要内容,如果未能解决你的问题,请参考以下文章

从零开始手写Tomcat的教程8节----加载器

6. 通过demo分析自定义类加载器以及Launcher源码分析

类加载器子系统

自定义一个类加载器打印“Hello World!”

自定义一个类加载器打印“Hello World!”

Android 逆向类加载器 ClassLoader ( 加载 Android 组件的类加载器 | 双亲委派机制实例分析 )