ClassLoader&双亲委派模型

类加载器的作用:

  • 类加载,通过类的权限定名获取此类的二进制字节流
  • 确定被加载的类在jvm中的唯一性

两个类是否相等的依据:是否由同一个ClassLoader加载

两个类是否相等的判断:

  • equals
  • isAssignableFrom
  • isInstance
类加载器的类型:
  1. 启动类加载器(Bootstrap ClassLoader)
  • 用于加载存放在\lib目录下和被-Xbootclasspath参数指定的类(事先定义好的类)
  • 仅按文件名识别,如:rt.jar,名字不符合的类库即使放在lib目录中也不会被加载
  • 无法被java程序直接使用
  1. 扩展类加载器(Extension ClassLoader)
  • 加载JAVA_HOME>\lib\ext目录中和被java.ext.dirs系统变量所指定的路径中的类
  • 开发者可以直接使用扩展类加载器
  1. 应用程序类加载器
  • 负责加载 用户类路径(ClassPath)上所指定的类库
  • 该类加载器是ClassLoader中的getSystemClassLoader()方法的返回值

双亲委派模型

双亲委派模型

注意点:

  • 除了顶层的启动类加载器,所有的加载器都有父类加载器
  • 加载器之前的关系是组合关系来复用父类加载器的代码,不是继承
双亲委派模型的工作流程代码实现在java.lang.ClassLoader的loadClass()
protected Class loadClass(String name, boolean resolve) 
        throws ClassNotFoundException { 
    Class c = findLoadedClass(name); 

  // 检查需要加载的类是否已经被加载过
    if (c == null) { 
        try { 
             // 若没有加载,则调用父加载器的loadClass()方法
            if (parent != null) { 
                c = parent.loadClass(name, false); 
            }else{ 
                // 若父类加载器为空,则默认使用启动类加载器作为父加载器
                c=findBootstrapClassOrNull(name); 
            } 
        } catch (ClassNotFoundException e) { 
            // 若父类加载器加载失败会抛出ClassNotFoundException, 
            //说明父类加载器无法完成加载请求 
        } 
        if(c==null){ 
            // 在父类加载器无法加载时 
            // 再调用本身的findClass方法进行类加载 
            c=findClass(name); 
        } 
    } 
    if(resolve){ 
        resolveClass(c); 
    } 
    return c; 
}
加载流程:
  1. 当一个加载器收到加载请求需求时,会提交给他的父类加载器去完成
  2. 只有当父类加载器反馈无法加载时,自己才会去加载
优点:

类加载器的层级关系保证了java类的带优先级的层次关系:

  • Object类只有启动类加载器会加载,所以只会有一个Object类,如果没有双亲委派模型,多个类加载加载Object类会出现多个Object类,无法保证java的最基础行为;

安卓的类加载器

  • BootClassLoader:加载framework中的类,如Activity.class
  • PathClassLoader:加载项目中的类,如MainActivity.class,其父加载器是BootClassLoader
  • DexClassLoader:加载指定目录的类,其父加载器也是BootClassLoader
  • InMemoryClassLoader:加载内存中的类,不如字节数组(类似动态代理中的那个东西)

类加载器加载类的原理:

BaseDexClassLoader:
  private final DexPathList pathList;

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
...
        Class c = pathList.findClass(name, suppressedExceptions);
...
    }
DexPathList:
    private Element[] dexElements;

    public Class findClass(String name, List suppressed) {
        for (Element element : dexElements) {
            Class clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        return null;
    }

    private static Element[] makeDexElements(List files, File optimizedDirectory,
            List suppressedExceptions, ClassLoader loader, boolean isTrusted) {
      Element[] elements = new Element[files.size()];
      int elementsPos = 0;
      /*
       * Open all files and load the (direct or contained) dex files up front.
       */
      for (File file : files) {
          if (file.isDirectory()) {
              // We support directories for looking up resources. Looking up resources in
              // directories is useful for running libcore tests.
              elements[elementsPos++] = new Element(file);
          } else if (file.isFile()) {
              String name = file.getName();

              DexFile dex = null;
              if (name.endsWith(DEX_SUFFIX)) {
                  // Raw dex file (not inside a zip/jar).
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                      if (dex != null) {
                          elements[elementsPos++] = new Element(dex, null);
                      }
                  } catch (IOException suppressed) {
                      System.logE("Unable to load dex file: " + file, suppressed);
                      suppressedExceptions.add(suppressed);
                  }
              } else {
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                  } catch (IOException suppressed) {
                      /*
                       * IOException might get thrown "legitimately" by the DexFile constructor if
                       * the zip file turns out to be resource-only (that is, no classes.dex file
                       * in it).
                       * Let dex == null and hang on to the exception to add to the tea-leaves for
                       * when findClass returns null.
                       */
                      suppressedExceptions.add(suppressed);
                  }

                  if (dex == null) {
                      elements[elementsPos++] = new Element(file);
                  } else {
                      elements[elementsPos++] = new Element(dex, file);
                  }
              }
              if (dex != null && isTrusted) {
                dex.setTrusted();
              }
          } else {
              System.logW("ClassLoader referenced unknown path: " + file);
          }
      }
      if (elementsPos != elements.length) {
          elements = Arrays.copyOf(elements, elementsPos);
      }
      return elements;
    }

    private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
                                       Element[] elements)
            throws IOException {
        if (optimizedDirectory == null) {
            return new DexFile(file, loader, elements);
        } else {
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
        }
    }

Element: DexPathList的一个静态内部类
       private final DexFile dexFile;

        public Class findClass(String name, ClassLoader definingContext,
                List suppressed) {
            return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
                    : null;
        }

dexFile.loadClassBinaryName()是一个native方法


https://blog.csdn.net/qq_22393017/article/details/81811101

你可能感兴趣的:(ClassLoader&双亲委派模型)