类加载器分类
- 引导类加载器(启动类加载器)(BootStrapClassLoader)
- 扩展类加载器(ExtClassLoader)
- 系统类加载器(AppClassLoader)
- 用户自定义加载器
也可以分为两类:引导类(启动类)加载器和继承自ClassLoader的加载器
几种类加载器的使用
-
BootStrapClassLoader
- 加载java核心类库
- 加载resource.jar或sun.boot.class.path路径下的内容
- 加载ExtClassLoader和AppClassLoader,并指定为它们的父类加载器
- 没有父类加载器。
- 由C/C++语言实现,嵌套在JVM内部
-
ExtClassLoader
-
从java.ext.dirs系统属性所指定的目录中加载类库
-
加载JDK安装目录的jre/lib/ext目录下的类,如果用户自定义的jar也放在此目录下,也会由扩展类加载器加载
-
其父类加载器为BootStrapClassLoader
-
由java语言编写,派生于ClassLoader
-
-
AppClassLoader
- 加载器加载环境变量classpath或系统属性java.class.path指定路径下的类库
- 用户自定义的类一般都在classpath路径下,所以用户自定义类一般由AppClassLoader加载
- 是程序中默认的加载器
- 其父类加载器为ExtClassLoader
- 由java语言编写,派生于ClassLoader
-
用户自定义类加载器
- 一般不会使用到用户自定义加载器,在以下场景会使用到用户自定义类加载器
- 隔离加载类
- 修改类加载方式
- 扩展加载源
- 防止源码泄漏
- 实现用户自定义类加载器步骤
- 继承抽象类java.lang.ClassLoader
- 把自定义的类加载逻辑写在findClassLoader()方法中(重写findClassLoader())
- 如果没有太过复杂的需求,可以直接继承URLClassLoader类,使自定义类加载器编写更加简洁
- 一般不会使用到用户自定义加载器,在以下场景会使用到用户自定义类加载器
获取类的方式
- clazz.getClassLoader(),获取当前类的ClassLoader
- Thread.currentThread().getClassLoader(),获取当前线程上下文的ClassLoader
- ClassLoader.getSystenClassLoader().getParent(),获取系统的扩展类加载器
- DriverManager.getCallerClassLoader(),获取调用者的ClassLoader
双亲委派机制
- java虚拟机对类的加载是按需加载
- 工作原理:
- 如果一个类加载器收到了类加载请求,他并不会自己先去加载,而是把这个请求委托给父类加载器去执行;
- 如果父类加载器还存在父类加载器,则进一步向上委托,一次地柜,请求最终将到达顶层的启动类加载器;
- 如果父类加载器可以完成加载任务,九成宫返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
- 优势:
- 避免类的重复加载
- 保护程序安全,防止核心API被随意修改
- 沙箱安全机制:对java核心源代码的保护
在JVM中表示两个class对象是否为同一个类存在两个必要条件
- 类的完整类名必须一致,包括包名
- 加载这两个类的ClassLoader(指ClassLoader实例对象)必须相同