摘自: https://www.cnblogs.com/heihaozi/p/12143308.html
类加载器简介
在介绍双亲委托模型之前, 先介绍一下类加载器. 类加载器通过一个类的全限定名来转换为描述这个类的二进制字节流.
对于任意一个类, 被同一个类加载器加载后都是唯一的, 但如果被不同加载器加载后, 就不是唯一的了. 即使是源于同一个 Class 文件, 被同一个 JVM 加载, 只要加载类的加载器不同, 那么类就不同.
如何判断类是否相同, 可以使用 Class 对象的 equals() 方法, isAssignableFrom() 方法, isInstance() 方法的返回结果进行判断, 也可以使用 instanceof 关键字进行对象所属关系的判断.
下面我们写一个不同类加载器加载后的类, 看一下对 instanceof 关键字运算有什么影响:
- public class OneMoreStudy {
- public static void main(String[] args) throws Exception {
- ClassLoader myLoader = new ClassLoader() {
- @Override
- public Class loadClass(String name) throws ClassNotFoundException {
- try {
- String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
- InputStream inputStream = getClass().getResourceAsStream(fileName);
- if (inputStream == null) {
- return super.loadClass(name);
- }
- byte[] array = new byte[inputStream.available()];
- inputStream.read(array);
- return defineClass(name, array, 0, array.length);
- } catch (IOException e) {
- throw new ClassNotFoundException(name);
- }
- }
- };
- Object object = myLoader.loadClass("OneMoreStudy").newInstance();
- System.out.println("class name:" + object.getClass().getName());
- System.out.println("instanceof:" + (object instanceof OneMoreStudy));
- }
- }
运行结果:
- class name: OneMoreStudy
- instanceof: false
在运行结果中, 第一行可以看出这个对象确实是 OneMoreStudy 类实例化出来的, 但在第二行中 instanceof 运算结果是 false, 说明在 JVM 中存在两个 OneMoreStudy 类, 一个是由系统应用程序类加载器加载的, 另一个是由我们自定义的类加载器加载的. 虽然都是来自同一个 Class 文件, 在同一个 JVM 里, 但是被不同的类加载器加载后, 仍然是两个独立的类.
类加载器的划分
除了像上面例子代码中, 我们自己实现的自定义类加载器, 还有 3 种系统提供的类加载器:
启动类加载器 (Bootstrap ClassLoader): 它负责将存放在 %JAVA_HOME%\lib 目录中的, 或者被 - Xbootclasspath 参数所指定的路径中的, 并且是 JVM 识别的类库加载到 JVM 内存中. 它仅按照文件名识别, 如 rt.jar, 名字不符合的类库即使放在 lib 目录中也不会被加载. 它是由 C++ 语言实现的, 无法被 Java 程序直接引用.
扩展类加载器 (Extension ClassLoader): 它负责加载 %JAVA_HOME%\lib\ext 目录中的, 或者被 java.ext.dirs 系统变量所指定的路径中的所有类库. 它由 sun.misc.Launcher.ExtClassLoader 实现, 开发者可以直接使用扩展类加载器.
应用程序类加载器 (Application ClassLoader): 它负责加载用户类路径 (ClassPath) 上所指定的类库. 由于它是 ClassLoader 中的 getSystemClassLoader() 方法的返回值, 所以一般也称它为系统类加载器. 它由 sun.misc.Launcher.AppClassLoader 来实现, 开发者可以直接使用这个类加载器, 如果应用程序中没有自定义过自己的类加载器, 一般情况下这个就是程序中默认的类加载器.
- protected Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- synchronized (getClassLoadingLock(name)) {
- // 首先, 检查该类是否已经被加载过了
- Class c = findLoadedClass(name);
- // 如果没有加载过, 就调用父类加载器的 loadClass() 方法
- if (c == null) {
- long t0 = System.nanoTime();
- try {
- if (parent != null) {
- c = parent.loadClass(name, false);
- } else {
- // 如果父类加载器为空, 就使用启动类加载器
- c = findBootstrapClassOrNull(name);
- }
- } catch (ClassNotFoundException e) {
- // 如果在父类加载器中找不到该类, 就会抛出 ClassNotFoundException
- }
- if (c == null) {
- // 如果父类找不到, 就调用 findClass() 来找到该类.
- long t1 = System.nanoTime();
- c = findClass(name);
- // 记录统计数据
- sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
- sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
- sun.misc.PerfCounter.getFindClasses().increment();
- }
- }
- if (resolve) {
- resolveClass(c);
- }
- return c;
- }
- }
来源: http://www.bubuko.com/infodetail-3364736.html