如何理解java的类加载器ClassLoader

时间:2021-06-14 16:22:48

      看了很多java的基础教程,对类加载器的理解都比较模糊。总结了几位博主的分析,由此对类加载器有了深入一点的认识。

      以下部分来自百度文库:

      与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。
JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,BootstrapClassLoader是用本地代码实现的,它负责加载核心JavaClass(即所有java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用Java语言编写的,由BootstrapClassLoader加载;其中Extension ClassLoader负责加载扩展的Javaclass(例如所有javax.*开头的类和存放在JRE的ext目录下的类),ApplicationClassLoader负责加载应用程序自身的类。
      当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。

      当决定创建你自己的ClassLoader时,需要继承java.lang.ClassLoader或者它的子类。在实例化每个ClassLoader对象时,需要指定一个父对象;如果没有指定的话,系统自动指定ClassLoader.getSystemClassLoader()为父对象。所以当创建自己的Class Loader时,只需要重载findClass()这个方法。

      以下部分转自http://blog.csdn.net/wxwzy738/article/details/8532123

      类加载器之间的父子关系(注:并非真正的继承,只是定义上的,不是针对类而是针对对象来说,即孩子有一个指向父亲的引用):

如何理解java的类加载器ClassLoader   

      一般类加载器的加载过程如下:
 
      调用 findLoadedClass() 来查看是否存在已装入的类。
      如果没有,那么获取class文件的原始字节。(通过IO从文件系统,来自网络的字节流等)
      如果已有原始字节,调用 defineClass() 将它们转换成 Class 对象。
      如果没有原始字节,然后调用 findSystemClass() 查看是否从本地文件系统获取类
      如果 resolve 参数是 true,那么调用 resolveClass() 解析 Class 对象。
      如果还没有类,返回 ClassNotFoundException。
      否则,将类返回给调用程序。
 
      类加载器的委托机制:
  
      当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
      首先当前线程的类加载器去加载线程中的第一个类。
      如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
      还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
      每个类加载器加载类时,又先委托给其上级类加载器。
      当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
      对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

      每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模式。类装载 器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。
 
      以下部分来自 bbs.itheima.com/thread-51369-1-1.html
 
      简单的说: 加载某个类时,优先使用父类加载器加载需要使用的类。如果我们自定义了java.lang.String这个类,加载该自定义的String类,该自定义String类使用的加载器是AppClassLoader,根据优先使用父类加载器原理,AppClassLoader加载器的父类为ExtClassLoader,所以这时加载String使用的类加载器是ExtClassLoader但是类加载器ExtClassLoaderjre/lib/ext目录下没有找到String.class类。然后使用ExtClassLoader父类的加载器BootStrap父类加载器BootStrapJRE/lib目录的rt.jar找到了String.class,将其加载到内存中。这就是类加载器的委托机制。