黑马程序员--类加载器

本文介绍了Java虚拟机中的类加载器,包括类加载器的父子关系树结构和类加载的父类委托机制。重点讲解了如何自定义类加载器,涉及loadClass方法的内部原理以及findClass方法的覆盖,以及如何使用defineClass方法将二进制数据转换为字节码。
摘要由CSDN通过智能技术生成

               ------------android培训java培训、期待与您交流!--------------


一、类加载器概述

Java虚拟机中可以安装多个类加载器,系统默认有三个主要的类加载器,每个类加载器负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader。类加载器也是Java类,因此java类的类加载器本身也要被其他的类加载器加载,显然必须有第一个类加载器不是java类,它就是BootStrap类加载器。
示例代码:


public class ClassLoaderTest {
       public static void main(String[] args) {
            System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
             //结果:sun.misc.Launcher$AppClassLoader
            System. out.println(System.class.getClassLoader());
             //结果:null
      }
}
根据以上的结果可以判断ClassLoaderTest类是由AppClassLoader类加载器加载的,System类是由BootStrap类加载器加载的,因为 BootStrap是由java虚拟机提供,它在JVM内核启动的时就已经被加载,是用c++编写的二进制对象,不需要其他类加载器加载,所以返回的结果是null。

Java虚拟机中的所有类装载器采用了具有父子关系的树形结构进行组织。下列代码将打印出所有的类加载器,示例代码如下:

public class ClassLoaderTest {
       public static void main(String[] args) {
            ClassLoader loader = ClassLoaderTest.class.getClassLoader();
             while(loader != null){
                  System. out.println(loader.getClass().getName());
                  loader = loader.getParent();
            }
            System. out.println(loader);
             /*结果:
               sun.misc.Launcher$AppClassLoader
               sun.misc.Launcher$ExtClassLoader
               null*/
      }

}

由上面的示例可以看到AppClassLoader类加载器的父级别类加载器是ExtClassLoader类加载器,ExtClassLoader类加载器的父级别类加载器是BootStrap类加载器。在实例化每个类加载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。 

二、类加载器之间的父子关系和管辖范围图


三、类加载器的委托机制
问题:当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1、首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
2、每个类加载器加载类时,又先委托给其上级类加载器。 当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,也不知道找哪一个。
注意:
1-每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模式。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。
2- 有一道面试题,能不能自己写个类叫java.lang.System?
答案是不能,即使写了也不会被类加载器加载。为了不让我们写System类,类加载机制采用委托机制,这样可以保证父级类加载器优先,也就是总是使用父级类加载器能找到的类,结果就是总是使用java系统自身提供的System类,而不会使用我们自己所写的System类。

四、编写自己的类加载器

类加载器中的loadClass方法内部实现了父类委托机制,因此我们没有必要自己覆盖loadClass,否则需要自己去实现父类委托机制。我们只需要覆盖findClass方法。loadClass方法中调用了findClass方法,使用的是模板设计模式。我们得到了Class文件后,就可以通过defineClass方法将二进制数据转换成字节码。这就是自定义类加载器的编写原理。

示例代码:

     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;
         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }
         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }




               ------------android培训java培训、期待与您交流!--------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值