类的四种引用
强引用
强引用是最常见的引用,如果对象被强引用,那垃圾回收器绝对不会回收它,即使抛出 OutOfMeoryError 错误、程序异常终止也不会进行回收
如:Object o = new Object();,所以如果强引用对象不使用时,可以弱化强引用对象从而使 GC 回收:o = null;
软引用
如果内存充足时,不会进行回收,如果内存不足时,会进行回收
弱引用
不管当前内存空间是否充足,都会进行回收
虚引用
虚引用被用于在对象被销毁之前进行必要的清理工作,例如关闭文件、释放系统资源等任务。通常情况下,虚引用不会单独使用,而是和队列一起使用,称为"虚引用队列"。虚引用队列的作用是在对象被垃圾回收器回收之前,将对象添加到队列中,以便在对象被回收后可以执行一些清理工作。
类的加载
类的加载顺序
- 加载:在堆中生成 Class 对象;
- 验证:确保类的正确性,如语法、命名规范等;
- 准备:为类的静态变量分配内存,并将其初始化为默认值;
- 解析:把类中的符号引用转换为直接引用;
- 初始化:为类的静态变量赋予正确的初始值,初始化顺序依次是:(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;如果有父类,则顺序是:父类 static 方法 –> 子类 static 方法 –> 父类构造方法- -> 子类构造方法;
- 使用
- 卸载
加载方式
- 由 JVM 初始化加载;
- 通过
Class.forName()方法动态加载; - 通过
ClassLoader.loadClass()方法动态加载;
Class.forName() 和ClassLoader.loadClass() 的区别
Class.forName()加载的类会被初始化,类中的静态成员变量会被初始化,静态代码块会被执行ClassLoader.loadClass()加载的类不进行解析操作,不进行解析操作就意味着初始化也不会进行,那么其类的静态参数就不会初始化,静态代码块也不会被执行。
类加载器
- 根类加载器:它用来加载 Java 的核心库,是用原生代码来实现;
- 扩展类加载器:它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录;
- 系统类加载器:它根据 Java 应用的类路径来加载 Java 类。Java 应用的类都是由它来完成加载;
双亲委派模式
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,只有当父加载器无法完成该加载,子加载器才会尝试自己去加载
双亲委派模式的好处
可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,Java 核心 API 中定义类型不会被随意替换
Tomcat 类加载器为何违背双亲委派模型
一个 Tomcat 里面可能方好几个项目,一个项目里面就是一个包,每一个项目使用的工具可能都不一样,对应的版本可能也不一样。