目录
一、类加载的过程
1、加载
2、连接
(1)、验证
(2)、准备
(3)、解析
3、初始化
二、类加载的触发
三、双亲委派模型
1、定义
2、过程
3、优点
(1)、避免重复加载类
(2)、保证安全性
一、类加载的过程
程序想要运行就需要把依赖的“指令和数据”加载到内存中,而类加载就是把 .class文件加载到内存中得到类对象的过程。
1、加载
加载阶段是整个“类加载”过程中的第一个阶段,它和类加载不同,是用来找到 .class文件,并且读取文件内容。
加载阶段Java虚拟机需要完成以下过程:
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
2、连接
(1)、验证
验证阶段的目的是确保 .class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。
(2)、准备
准备阶段是正式为类中定义的变量(静态变量)分配内存空间并设置类变量初始值。未初始化的空间,内存空间中的数据全是0,类对象中的静态成员也是全0。
(3)、解析
解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程,也就是针对字符串常量进行初始化的过程。
字符串常量在 .class文件中就存在,它们只是知道彼此之间的相对位置(偏移量)而不知道自己在内存中的实际地址。
此时的字符串常量就是符号引用,真正加载到内存中就会把字符串常量填充到内存中的特定地址上。字符串常量之间的相对位置虽然是一样的,但这些字符串有自己真正的内存地址。此时的字符串就是直接引用即Java中的普通引用
3、初始化
初始化阶段就是执行类构造器方法的过程,是Java虚拟机真正开始执行类中编写的Java程序代码,将主导权移交给应用程序的阶段。
初始化阶段针对类对象直接进行初始化:初始化静态成员,执行静态代码块,加载父类。
二、类加载的触发
类加载整体是一个“懒加载”的策略(懒汉模式——非必要、不加载),而不是JVM一启动就把所有的 .class都加载的。
类加载是在以下的场景才进行触发:
- 创建了这个类的实例
- 使用了这个类的静态方法/静态属性
- 使用子类会触发父类的加载
三、双亲委派模型
1、定义
双亲委派模型所做的工作就是在类加载的第一个步骤中找到 .class文件的过程。JVM中加载类需要用到一组特殊的模块——类加载器
在JVM中内置了三个类加载器:
- BootStrap ClassLoader:负责加载Java标准库中的类
- Extension ClassLoader:负责加载一些非标准的,但是Sun/Oracle扩展的库的类
- Application ClassLoader:负责加载项目中自己写的类以及第三方中的类
2、过程
双亲委派模型是类加载机制中一个较为重要的机制,如果一个类加载器收到了类加载的请求,它不会自己先去尝试加载这个类,而是把这个请求委派给父类加载器去完成。每一层的类加载器都进行该操作,因此所有的加载请求最终都会传送到最顶层的启动类加载器中。只有当父加载器反馈自己没有找到所需的类时,子加载器才会尝试自己去完成加载。
3、优点
(1)、避免重复加载类
当A类和B类都有一个父类C类时,当A类启动时就会将C类加载,而在B类进行加载时就不需要在重复加载C类。
(2)、保证安全性
使用双亲委派模型可以保证Java的核心API不被篡改。
如果没有使用双亲委派模型,而是每个类加载器加载自己的就会出现一些问题。当我们编写一个称为java.lang.Object类时,程序运行系统就会出现多个不同的Object类,而有些Object类又是用户自己提供的因此安全性就不能得到保证。