JVM中类加载的过程(面试考点)

类加载

含义:把.class文件加载到内存,得到 类对象 的过程。 对于引用数据类型则需要进行类的加载。
类的生命周期:加载->验证->准备->解析->初始化->使用->卸载。其中,验证,准备,解析3个部分统称为连接。
触发时间:类加载不是JVM一启动就把所有.class文件都加载了,而是一个"懒加载"的策略(懒汉模式),非必要不加载
其中什么是必要:

  • 创建了这个类的实例
  • 使用了这个类的静态方法或者静态属性
  • 使用子类,会触发父类的加载

类加载的过程

加载(Loading)

在加载过程中,JVM(Java虚拟机)需完成以下三件事:

  • 通过一个类的全限定名来获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区运行时的数据结构
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

在加载阶段,简言之就是找到.class文件,并且读取文件内容
对于找到.class文件这个过程,就是双亲委派模型所做的事。

验证(Verification)

连接阶段的第一步。验证的目的是确保Class文件的 字节流 中包含的信息符合《Java虚拟机
规范》的全部约束要求,保证这些信 息被当作代码运行后不会危害虚拟机自身的安全。
简言之:验证的目的是保证加载的字节码是合法,合理并符合规范的
字节码:在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件)
验证的选项:

  • 文件格式验证
  • 字节码验证
  • 符号引用验证…

准备(Preparation)

给类对象分配内存空间(未初始化的空间,内存空间的数值全为0)
简言之,为类的静态变量分配内存,并将其初始化为默认值
例如:

public static int a = 123;
其中初始化 a 的 int 值为0,而不是123.

Java 虚拟机为各类型变量默认的初始值如下:
1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。

2、单精度浮点型(float)的基本类型变量的默认值为0.0f。

3、双精度浮点型(double)的基本类型变量的默认值为0.0d。

4、字符型(char)的基本类型变量的默认为 “/u0000”。

5、布尔型(boolean)的基本类型变量的默认值为 false。

6、引用类型的变量是默认值为 null。

解析(Resolution)

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。
针对字符串常量进行初始化。

通过解析操作,符号引用就可以转变为目标方法在类中方法表中的位置,从而使得方法被成功调用

符号引用:字符串常量在.class文件中就存在了,在这里面,它们只知道彼此之间的相对位置(即偏移量),但它们不知道自己在内存中的实际地址。这时的这个字符串常量就是符号引用
直接引用:加载到内存中,就会把字符串常量填充到内存中的特定地址上,其中字符串常量彼此之间的相对位置还是一样的,但它们此时已经在内存上有了自己的特定地址(真正的内存地址)。此时的字符串常量就是直接引用

初始化(Initialization)

初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。初始化阶段就是执行类构造器方法的过程
简言之,为类的静态变量赋予正确的初始值针对类对象进行初始化
到了初始化阶段,才真正开始执行类中定义的 Java 程序代码

双亲委派模型

含义:就是在 加载过程中,找到.class文件
在JVM中,加载类需要用到类加载器,JVM中内置了3个类加载器

  1. BootStrap ClassLoader :负责加载Java标准库中的类
  2. Extension ClassLoader :负责加载一些非标准但是Sun/Oracle扩展库的类
  3. Application ClassLoader : 负责加载项目中自己写的类以及第三方库中的类

过程

首先,先需要给定一个类的全限定类名,例如java.lang.String(是一个字符串)
全限定类名:包名 + 类型名 。 带包路径用点隔开

先从Application ClassLoader出发进行加载,让Application ClassLoader进行文件搜索,但在这里,Application ClassLoader不能先开始搜索,而是要先上报给它的父亲Extension ClassLoader,在这里面,Extension ClassLoader也一样,也要上报给它的父亲BootStrap ClassLoader,而此时BootStrap ClassLoader也要上报给它的父亲 ,但是BootStrap ClassLoader没父亲,所以它自己开始搜索。
在上述它们3个类加载器其实就是父子关系。
在这里插入图片描述

注意:上述双亲委派模型也是可以打破的。在Java中,允许程序员自定义类加载器,你可以遵循上述过程,也可以不遵循上述过程。

优点

  • 避免重复加载类:若A类和B类都有一个父类C类,那么当A类启动时就会将C类加载起来,此时当B类再启动时就不会再次加载C类了
  • 安全性提高使用双亲委派模型可以保证Java的核心API不会被篡改。 若没有使用双亲委派模型,让每个类加载器加载自己的话,就会出现一些问题,比如我们编写一个全限定类名为 java.lang.Object类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户自己提供的因此安全性就不能得到保证了。

缺点

只适应大部分情况,在某些情况下也会存在问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值