[JVM] 3. 类加载子系统(2)-- 类加载器、双亲委派机制(JDK1.8及之前)及其他

前言

JDK1.8及之前和JDK9及之后的双亲委派模型是不一样的,这里学习了1.8及以前的双亲委派模型,记录笔记

一、类加载器

1.8之前主要是这几种类加载器:

1. 启动类加载器(Bootstrap ClassLoader):

  • 负责将存放在\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名,如rt.jar)类库加载到虚拟机内存中。(核心类)
  • 启动类加载器无法被java程序直接引用,用户在编写自定义类加载器时,若需要把加载请求委派给引导类加载器,直接用null代替即可。
  • 加载扩展类和应用程序类加载器,并指定为他们的父加载器
  • 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

        启动类加载器(Bootstrap ClassLoader)是用c/c++实现的,嵌在JVM内部,并不是继承java.lang.ClassLoader。

        启动类加载器(Bootstrap ClassLoader)对Java不可见,获取是null,因此可以通过某一个类的加载器是否为null来判断该类是不是使用BootstrapClassLoader进行加载。

2. 扩展类加载器(Extension ClassLoader):

  • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现。
  • 派生于ClassLoader类
  • 父加载器为启动类加载器(Bootstrap ClassLoader)
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/1ib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

3. 应用程序类加载器(Application ClassLoader):

  • 由sun.misc.Launcher$AppClassLoader实现,是ClassLoader中的getSystemClassLoader()方法的返回值,被称为系统类加载器,负责加载用户类路径(classpath)上所指定的类库。

[JVM] 3. 类加载子系统(2)-- 类加载器、双亲委派机制(JDK1.8及之前)及其他_第1张图片

 启动类加载器是扩展类加载器的父加载器,但是不能说二者是父子类关系。其他加载器的关系也同理。(读作 父 类加载器)

二、双亲委派机制(JDK1.8及之前)

        如果一个类加载器收到了类加载请求,首先它不会尝试加载这个类,而是把这个任务委托给父类加载器,每一层都是这样。因此,所有的加载请求应该都传送到顶层的启动类加载器(Bootstrap ClassLoader)。

        只有当父 类加载器反馈自己无法加载这个类时,子 类加载器才会尝试加载该类。        

[JVM] 3. 类加载子系统(2)-- 类加载器、双亲委派机制(JDK1.8及之前)及其他_第2张图片

优点:

  1. 避免了类的重复加载
  2. 保护了程序的安全性,防止核心的API被修改

三、其他

1. 沙箱安全机制:

        自定义String类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的string类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

2. 如何判断两个class对象是否相同:

        在JVM中表示两个class对象是否为同一个类存在两个必要条件:

  • 类的完整类名必须一致,包括包名。
  • 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。

        换句话说,在JVM中,即使这两个类对象(class对象)来源同一个Class文件,被同一个虚拟机所加载,但只要加载它们的ClassLoader实例对象不同,那么这两个类对象也是不相等的。

3. 对类加载器的引用​​​​​​​:

        JVM必须知道一个类型是由启动加载器(Bootstrap ClassLoader)加载的还是由用户类加载器加载的。

        如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JVM需要保证这两个类型的类加载器是相同的。

        

4. 类的主动使用和被动使用:​​​​​​​

Java程序对类的使用方式分为:主动使用和被动使用。

主动使用,又分为七种情况:

  • 创建类的实例 
  • 访问某个类或接口的静态变量,或者对该静态变量赋值 
  • 调用类的静态方法 
  • 反射(比如:Class.forName("com.atguigu.Test")) 
  • 初始化一个类的子类 
  • Java虚拟机启动时被标明为启动类的类 
  • JDK 7 开始提供的动态语言支持:
    java.lang.invoke.MethodHandle实例的解析结果
    REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化 

除了以上七种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化。

参考:

面试必问的 JVM 类加载机制,你懂了吗?_程序员囧辉的博客-CSDN博客

双亲委派机制_云飘飘啊的博客-CSDN博客​​​​​​​

2. 类加载子系统 · 语雀

双亲委派机制 - 知乎

你可能感兴趣的:(JVM,jvm,java,开发语言)