Java类加载机制
Posted long518
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java类加载机制相关的知识,希望对你有一定的参考价值。
一、什么是类的加载
定义:类的加载是指将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆中创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
二、什么时候启动类的加载器
某个类被“首次主动使用”时加载它,或类加载器在预料某个类将要被使用时就预先加载它
三、类加载的过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
类加载的过程包括了加载、验证、准备、解析、初始化五个阶段
1、加载
① 通过类的全限定名来获取类的二进制字节流;
② 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构;
③ 在堆生成一个代表该类的Class对象,作为方法区中这些数据的访问入口;
2、验证
主要是确保被加载类的正确性
① 文件格式的验证:验证.class文件字节流是否符合class文件规范;
② 元数据验证:主要对字节码描述的信息进行语义分析,以保证其描述的信息符合java语法规定;
③ 字节码验证:主要是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的;
④ 符号引用验证:发生在虚拟机将符号引用转化为直接引用的时候。主要是对类自身以外的信息进行校验。目的是确保解析动作能够完成。
3、准备
- 准备阶段主要为类变量分配内存并设置初始值
- 类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中
- 这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值
4、解析
解析阶段主要是虚拟机将常量池中的符号引用转化为直接引用的过程。
-
符号引用:即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。
-
直接引用:可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量。
举个例子来说,现在调用方法hello(),这个方法的地址是0xaabbccdd,那么hello就是符号引用,0xaabbccdd就是直接引用。
在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。
5、初始化
- 初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。
- 如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
- 如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
6、使用
7、卸载
四、类加载器
1、JAVA语言系统自带有三个类加载器
① Bootstrap ClassLoader:加载核心类库,也就是我们环境变量下面%JRE_HOME%lib
② Extention ClassLoader:扩展的类加载器,加载目录%JRE_HOME%libext目录下的jar包和class文件
③ Appclass Loader:加载当前应用的classpath的所有类
二、双亲委派原则
- 工作原理:当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。
- 优点:① 可以避免重复加载,父类已经加载了,子类就不需要再次加载;
② 更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。
以上是关于Java类加载机制的主要内容,如果未能解决你的问题,请参考以下文章