一、类加载器
1.1 介绍
类加载器主要是一个负责加载类的对象
,确切的说是将 Java 源码经过编译之后生成的字节码文件(.class)从硬盘上加载 JVM 运行时数据区的堆上,将其转为可以执行的 Class 对象。每个类只有一个Class对象,
不论以哪种方式去获取类的 Class 对象,最终都是指向同一个。
每个 Java 类被类加载器加载到内存上,都会生成一个 Class 对象,而 Class 对象上维护了一个 ClassLoader 对象,指向加载该 Class 对象的类加载器,也就是说每个 Java 类都有一个引用指向加载该类的类加载器
。
Class 对象可以看成对类的描述或者说模板对象,保存了类的信息,包括类名、属性、方法、父类信息等等信息,可以通过
newInstance()
去创建类的实例对象。
1.2 三大
JVM 提供了三种类加载器,分别是应用类加载器、扩展类加载器和启动类加载器
- 应用程序类加载器 ApplicationClassLoader:也叫系统类加载器,面向用户,会去搜索并加载类路径
(classpath)
下的类。 - 扩展类加载器 ExtensionClassLoader:应用程序类加载器的父类加载器,加载Java扩展类库**(jre/lib/ext 目录下)**的类加载器,包括 javax 和 java.util 等。
- 启动类加载器BootstrapClassLoader:也叫根类加载器,扩展类加载器的父类加载器,是最顶层的类加载器,由C++实现,所以无法通过 Java 代码获取(返回为 null)。主要用来加载 JVM 的核心类库,如 java.lang。
1.3 加载规则
程序启动后,并不会一次性将所有类都加载到内存,而是根据实际需求去进行动态加载,也就是说大部分类只有在用到时,才会被类加载器加载到内存,避免了内存的浪费。
当一个类被加载时,也不会立即就被加载,而是会先判断该类是否被加载到内存中,如果已被加载,则直接返回,反之才会去加载,确保一个类只会被加载一次。
二、双亲委派机制
上述说过,JVM 提供了三个类加载器,其父子关系如下
原理
当一个类加载器接收到一个类加载请求时,该类加载器并不会立即加载该类,而是将这个加载请求委派给父类加载器·(调用父加载器 loadClass()方法来加载类)
,每个类加载器都是如此。
直到启动类加载器,启动类加载器会在自己的搜索方位内进行搜索,检查是否有该类,如果有,则启动类加载器直接加载该类,反之则向下通知子类加载器,子类加载器会尝试加载(调用自己的findClass()方法)
,以此类推,直到被加载为止。如果所有的类加载器都无法加载,则会抛出异常 。
俗话
- 应用程序启动
- 应用程序类加载器获得类加载请求
- 应用程序类加载器将请求委派给扩展类加载器
- 扩展类加载器将加载请求委派给启动类加载器
- 启动类加载器搜索自己能加载的范围,检查是否能加载
- 有该类则将其加载到内存上 (return)
- 没有则将加载请求通知给扩展类加载器
- 扩展类加载器搜索自己能加载的范围,检查是否能记载
- 有该类则将其加载到内存上 (return)
- 没有则将加载请求通知给应用程序类加载器
- 应用程序类加载器搜索自己能加载的范围,检查是否能记载
- 有该类则将其加载到内存上 (return)
- 没有则将加载请求通知给应用程序类加载器
JVM判断该类是否被加载的依据是判断类名以及加载该类的类加载器是否一致,一致便表示已被加载,反之则不是。不同类加载器加载同一个 Class 对象,也不是同一个 Class 对象。
好处
- 避免同一个类被重复加载
- 确保了 Java 核心类库不被篡改,确保了 Java 程序的稳定运行