一.加载
1.根据类的全限定名获取类的二进制数据流
2.解析类的二进制数据流在方法区生成动态的数据结构
3.在堆中生成对应的Class对象,作为方法区中的类数据的入口
数组类不是类加载器加载,而是由jvm在运行时根据需要加载。但是数组元素的类型是由类加载器加载。
二.链接
1.验证
验证class文件是否符合java虚拟机规范
2.准备
为类的静态变量分配内存,对类属性进行默认初始化
final类型的属性,在编译期就会分配了,在准备阶段显式赋值
3.解析
符号引用转换为直接引用
符号引用:用一组符合描述引用对象:(类和接口的全限定名,方法和字段的名称和描述符)
直接引用:直接指向引用对象的地址或偏移量
三.初始化
<clint>方法,对类中的属性进行显示赋值,只会执行一次,线程安全。
只有主动使用才会对类进行初始化操作
主动使用:
1.创建类实例:new ,反射,克隆,反序列化
2.调用类的静态方法
3.使用类的静态字段
4.使用反射类的方法
5.初始化子类
6.直接或间接实现接口的类的初始化,会导致接口的初始化
7.执行的主类(main方法所在的类)
8.初次调用MethodHandle实例,初始化MethodHandle指向的方法所在的类
四.static final 属性
1.如果是基本数据类型,或string字面量在准备阶段显式赋值,否则在初始化阶段显式赋值。
五.类的卸载
类的所有实例已经被回收
类的Class对象不再被引用
加载该类的加载器已经被回收
才允许被回收,不是一定。
六.类加载器
1.分类:
启动类加载器
自定义类加载器(继承自classloader):扩展类加载器,应用程序类加载器
2.类加载器的命名空间
类加载器和类本身一同确认其在java虚拟机中的唯一性
每个类加载器都有自己的命名空间,由该加载器及所有的父加载器所加载的类组成
3.类加载机制的基本特征
①双亲委派模型
当一个请求类加载器进行加载时,类加载器首先交给其父类加载器进行加载,一直向上委托,当父类加载器无法加载时,再由子类加载器进行加载
双亲委派模型的优势
保护核心类的安全,防止被篡改
避免类的重复加载
劣势
顶层的加载器无法访问底层的加载器所加载的类
破坏双亲委派机制
1.在jdk1.2之前,双亲委派模型还没有引入
2.线程上下文类加载器,默认是应用程序类加载器。spi机制,父类加载器请求子类加载器完成类加载的行为。
3.代码热替换,热部署
由于不同的classloader加载同一个类,在虚拟机内部,会认为这两个类完全不同。
②可见性
子类加载器可以访问父类加载器加载的实现
③单一性
由于父类加载对子类加载器可见,所以父类加载器加载过的类型,子加载器不会重复加载,但是类加载器邻居间,同一类型仍会加载多次。
4.自定义类的加载器
重写loadclass方法
重写findclass方法
1.读取字节码文件为字节数组
2.调用defineClass方法将字节数组的数据转换为Class实例
自定义类加载的用处
1.隔离加载类
2.修改类加载的方式
3.扩展加载源
4.防止源码泄露
5.jdk1.9新特性
①扩展类加载器被移除,被重命名为平台类加载器
②jdk 9的jar 进行了模块化的构建
②类加载器的委派关系发生了变化
当收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块,如果有归属关系,就要优先委派给负责的模块加载器进行加载