JVM之类加载的过程|Java 开发实战

711 阅读3分钟

这是我参与更文挑战的第 1 天,活动详情查看: 更文挑战

本文正在参加「Java主题月 - Java 开发实战」,详情查看活动链接

一、类的加载子系统与过程

1.类加载的子系统

类的加载子系统

类加载的子系统分为三个阶段:加载 --> 链接 --> 初始化

加载器的作用:

  1. 加载器只负责加载Class文件,并且Class文件在开头必须有特定的标识
  2. 加载器只负责加载Class文件,不管是否可以运行
  3. 加载后的类信息存放到方法区

2.类的加载过程

  • Loding(加载):通过全限定类名获取二进制字节流,把流转化为方法区的运行时数据结构,在内存中生成一个代表这个类的java.lang.Class对象,作为方法区中这个类的访问入口。(生成大Class实例)
  • Linking(链接):
    • Verify(验证):在加载后,确保被加载的Class文件字节流信息符合当前虚拟机的要求,不会危害虚拟机自身安全。
    • Prepare(准备):为变量分配内存,并且分配默认的初始值,零值。**注意:**如果被final修饰的static常量不会在这个阶段分配内存,而是在编译阶段就已经分配了,在准备阶段进行显示的初始化(值是多少就赋值为多少)。不会为实例变量初始化,对象还未创建。
    • Resolve(解析):将符号引用转换为直接引用,直接引用就是直接指向目标的指针,主要针对类、接口、字段、类方法、接口字段、方法类型等。
  • initialzation(初始化):初始化就是执行类的构造方法<client>()的过程,不是类的构造器。<client>()方法自动收集类变量的赋值动作和静态代码块,为类的常量赋值,如果没有这样的操作就没有该方法。如果有父类,会先执行父类的<client>()方法。<client>()方法在多线程下是同步加锁的,保证类只加载一次。此步骤之后,类才正式成为可执行状态。

3.类加载器

JVM的类加载器主要分为两种类型,一种是引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User Defined ClassLoader)。根据Java虚拟机规范中,所有派生于ClassLoader的加载器都是自定义类加载器。

加载器分类:

  • 引导类加载器(Bootstrap ClassLoader):

    • 只负责加载Java的核心类库(java、javax、sun等包),并且无法获取该加载器,C/C++语言实现。
  • 扩展类加载器(Extension ClassLoader):

    • 派生于ClassLoader类,主要加载JDK目录下的jre/lib/ext下的类库。如果用户创建的JAR在此目录下,也会被扩展类加载器加载。
  • 系统类加载器(Application ClassLoader):

    • 派生于ClassLoader类,主要加载自定义的类,程序默认的类加载器。
  • 用户自定义加载器:可以继承ClassLoader类,并且重写内部方法。(不常用)

4.双亲委派机制

原理:

在加载器收到一个加载类的请求时,加载器并不会直接加载,而是递归向上请求父类加载器,直到最顶层的Bootstrap ClassLoader,如果Bootstrap ClassLoader可以加载就成功返回,如果不能加载就依次向下请求,直到被成功加载。

双亲委派aaa

**注意:**如果接口属于核心API类库的,那么接口会被Bootstrap ClassLoader加载器加载,而接口的实现类会被默认的加载器Application ClassLoader加载,这就是所谓的反向委托。

优势:

  • 避免类的重新加载,因为类加载器具有层次关系,所以被加载器加载的类也就具有了这个层次关系。
  • 保护程序安全,防止核心API被随意篡改,比如自定义一个String类,在整个系统中都使用这个String,是不可以的。也称为沙箱安全机制。