关于类的加载

115 阅读3分钟

类的四种引用

强引用

强引用是最常见的引用,如果对象被强引用,那垃圾回收器绝对不会回收它,即使抛出 OutOfMeoryError 错误、程序异常终止也不会进行回收

如:Object o = new Object();,所以如果强引用对象不使用时,可以弱化强引用对象从而使 GC 回收:o = null;

软引用

如果内存充足时,不会进行回收,如果内存不足时,会进行回收

弱引用

不管当前内存空间是否充足,都会进行回收

虚引用

虚引用被用于在对象被销毁之前进行必要的清理工作,例如关闭文件、释放系统资源等任务。通常情况下,虚引用不会单独使用,而是和队列一起使用,称为"虚引用队列"。虚引用队列的作用是在对象被垃圾回收器回收之前,将对象添加到队列中,以便在对象被回收后可以执行一些清理工作。

类的加载

类的加载顺序

  1. 加载:在堆中生成 Class 对象;
  2. 验证:确保类的正确性,如语法、命名规范等;
  3. 准备:为类的静态变量分配内存,并将其初始化为默认值;
  4. 解析:把类中的符号引用转换为直接引用;
  5. 初始化:为类的静态变量赋予正确的初始值,初始化顺序依次是:(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;如果有父类,则顺序是:父类 static 方法 –> 子类 static 方法 –> 父类构造方法- -> 子类构造方法;
  6. 使用
  7. 卸载

加载方式

  1. 由 JVM 初始化加载;
  2. 通过Class.forName()方法动态加载;
  3. 通过ClassLoader.loadClass()方法动态加载;

Class.forName() 和ClassLoader.loadClass() 的区别

  • Class.forName() 加载的类会被初始化,类中的静态成员变量会被初始化,静态代码块会被执行
  • ClassLoader.loadClass() 加载的类不进行解析操作,不进行解析操作就意味着初始化也不会进行,那么其类的静态参数就不会初始化,静态代码块也不会被执行。

类加载器

  1. 根类加载器:它用来加载 Java 的核心库,是用原生代码来实现;
  2. 扩展类加载器:它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录;
  3. 系统类加载器:它根据 Java 应用的类路径来加载 Java 类。Java 应用的类都是由它来完成加载;

双亲委派模式

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,只有当父加载器无法完成该加载,子加载器才会尝试自己去加载

双亲委派模式的好处

可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,Java 核心 API 中定义类型不会被随意替换

Tomcat 类加载器为何违背双亲委派模型

一个 Tomcat 里面可能方好几个项目,一个项目里面就是一个包,每一个项目使用的工具可能都不一样,对应的版本可能也不一样。