类加载器与双亲委托模型

本文详细介绍了Java的类加载器,包括根类加载器、扩展类加载器、系统类加载器以及用户自定义类加载器。类加载遵循双亲委托模型,确保核心类库的安全。类的初始化步骤和命名空间的概念也进行了阐述。此外,讨论了类的卸载条件以及双亲委托模型带来的好处,如类型安全和防止类的重复加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有两种类型的类加载器

  1. Java虚拟机自带的加载器
    1. 根类加载器(Bootstrap)
    2. 扩展类加载器(Extension)
    3. 系统(应用)类加载器(System)AppClassLoader
  2. 用户自定义的类加载器
    1. Java.lang.ClassLoader的子类
    2. 用户可以定制类的加载方式

类加载器并不需要等到某个类被主动使用时再加载它

JVM规范允许类加载器再预料某个类将要被使用时就预先加载它,如果再预先加载的过程中遇到了.class文件缺失或者存在的错误,类加载器必须再程序首次主动使用该类时报告错误(LinkageError错误)

如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误

JVM类的初始化步骤

  1. 假如这个类还没有被加载和连接,那就先进行加载和连接
  2. 假如类存在直接父类,并且这个父类还没有被初始化,那么就先初始化直接父类
  3. 假如类中存在初始化语句,那就依次执行这些初始化语句

双亲委托模型:

  1. 当一个类被使用时会先去找到系统类加载器AppClassLoader是否存在。如果存在则返回,不存在则找到它的父加载器ExtClassLoader进行查找是否存在。如果存在则返回,不存在则在去找父加载器BootstrapClassLoader进行查找。如果存在则返回,不存在则由BootstrapClassLoader根类加载器尝试加载。成功则返回,失败则退回子加载器ExtClassLoader去尝试加载。成功则返回,失败则由子类加载器AppClassLoader进行加载,成功则返回,失败报错。

若有一个类加载器能够成功加载Test类,那么这个类加载器被称为定义类加载器,所有能够成功返回Class对象引用的类加载器(包括定义类加载器)都被成为初始类加载器

 * <p> {@code Class} objects for array classes are not created by class

 * loaders, but are created automatically as required by the Java runtime.

 * The class loader for an array class, as returned by {@link

 * Class#getClassLoader()} is the same as the class loader for its element

 * type; if the element type is a primitive type, then the array class has no

 * class loader.

注意数组类型并不是通过类加载器加载得到,而是通过JVM动态创建的,当数值类调用getClassLoader(),将获得数值类型的类加载器,当数组的类型是原始类型则没有类加载器。

例:

{
    String[] strings = new String[5];  
    strings.getClass().getClassLoader(); //结果为null;
    MyTest[] mytests = new MyTest[2]; 
    mytest.getClass().getClassLoader(); //结果为AppClassLoader 
}

类加载器的命名空间

  1. 每个类加载器都有自己的命名空间,命名空间由该加载器及所有的父加载器的类组成。
  2. 再同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类
  3. 在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类

注意父加载器加载的类无法访问子加载器加载的类,子加载器能够访问父加载器加载的类

类的卸载

  1. 当MySample类被加载、连接和初始化后,它的生命周期就开始了。当代表MySample类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,MySample类在方法区内的数据也会被卸载,从而结束Sample类的生命周期
  2. 一个类何时结束生命周期,取决于代表它的Class对象何时结束生命周期
  3. 由Java虚拟机自带的类加载器加载的类,在虚拟机的生命周期中,始终不会被卸载。包括根类加载器、扩展类加载器和系统类加载器。Java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的Class对象,因此这些Class对象始终是可触及的
  4. 由用户自定义的类加载器所加载的类是可以被卸载的

类双亲委托模型的好处:

  1. 可以确保java核心库的类型安全:所有的Java应用都至少会引用java.lang.Object这个类会被加载到java虚拟机中;如果这个加载过程由java应用自己的类加载器所完成的,那么很可能就会在JVM中存在多个版本的java.lang.Object,而这些类之间还是不兼容不可见的(正式命名空间在发挥作用)。借助于双亲委托机制,java核心类库中的类的加载工作都是由启动类(根类)加载器统一完成的,从而确保了java应用中确保了java所使用的都是统一版本的java核心类库,他们都是兼容的
  2. 确保java核心类库提供的类不会被自定义类所替代
  3. 不同的类加载器可以为相同名称(binary name)的类创建额外的命名空间,相同名称的类可以并存在java虚拟机中只需要通过不同的类加载器加载即可,不同类加载器所加载的类之间是不兼容的,这就相当于java虚拟机内部创建了一个又一个相互隔离的java类空间,这个技术在很多框架中得到了实际应用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值