这篇文章主要介绍了ClassLoader类加载的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
创新互联公司是专业的桂林网站建设公司,桂林接单;提供做网站、网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行桂林网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
Java类加载器
1、BootClassLoader: 用于加载Android Framework层class文件。
2、PathClassLoader: 用于Android应用程序类加载器。可以加载指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加载指定的dex,以及jar、zip、apk中的classes.dex


源码解析
1.ClassLoader中提供loadClass用于加载指定类
//ClassLoader.java
public Class> loadClass(String name) throws ClassNotFoundException {
 //该处调用了两个参数的重载方法
  return loadClass(name, false);
 }
 
 protected Class> loadClass(String name, boolean resolve)
  throws ClassNotFoundException
 {
  //先查一下该类是否已经加载过了
   Class> c = findLoadedClass(name);
   if (c == null) {
    try {
     //双亲委托机制,先让爸爸去找
     if (parent != null) {
      c = parent.loadClass(name, false);
     } else {
      //如果parent为null,则用BootClassLoader进行加载
      c = findBootstrapClassOrNull(name);
     }
    } catch (ClassNotFoundException e) {
     // ClassNotFoundException thrown if class not found
     // from the non-null parent class loader
    }
    if (c == null) {
     //如果都找不到就自己去找,此方法在子类BaseDexClassLoader类中有重写
     c = findClass(name);
    }
   }
   return c;
 }2.BaseDexClassLoader类中对findClass有重写,也是实际会使用执行的
//BaseDexClassLoader.java
//查找class
 @Override
 protected Class> findClass(String name) throws ClassNotFoundException {
  ...
  //这里通过pathList变量来查找,而pathList是在BaseDexClassLoader的构造方法中初始化的
  Class c = pathList.findClass(name, suppressedExceptions);
  ...
  return c;
 }
 
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
   String librarySearchPath, ClassLoader parent, boolean isTrusted) {
  super(parent);
  //构造方法中初始化pathList变量
  this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
 }3.BaseDexClassLoader中是通过调用DexPathList中的findClass来实现的,那么接下来我们分析一下DexPathList是怎么实现的
//DexPathList.java //是一个Element数组,一个element中包含一个 DexFile,DexFile就代表一个Dex文件,里面的native(C/C++)函数来进行Dex的加载工作 private Element[] dexElements; public Class> findClass(String name, Listsuppressed) { for (Element element : dexElements) { //此处调用Element的findClass来实现, Class> clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } return null; } // Element为DexPathList的内部类 static class Element { private final File path; //一个DexFile就代表一个Dex文件 private final DexFile dexFile; //有多个构造方法,但都仅是将值传过来,让Element来持有一个DexFile public Element(DexFile dexFile) { this.dexFile = dexFile; this.path = null; } public Class> findClass(String name, ClassLoader definingContext, List suppressed) { //通过DexFile来加载类 return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) : null; } } DexPathList(ClassLoader definingContext, String dexPath, String librarySearchPath, File optimizedDirectory, boolean isTrusted) { //通过makeDexElements方法为dexElements初始化 this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions, definingContext, isTrusted); } //腾讯系的热修复,诸如微信tinker、qq空间qfix原理便是反射此方法,将修复后的类打包成dex,通过反射该方法来将文件转化为Element,并将新生成的element放到dexElements前面,这样下次系统再去寻找某个class时,会先从修复后的dex中来找class,找到后便不再继续查找,从而修复该class,此方式便为插桩 private static Element[] makeDexElements(List files, File optimizedDirectory, List suppressedExceptions, ClassLoader loader, boolean isTrusted) { Element[] elements = new Element[files.size()]; ... for (File file : files) { if (name.endsWith(DEX_SUFFIX)) { //以 .dex 结尾的 // Raw dex file (not inside a zip/jar). //加载dex文件 dex = loadDexFile(file, optimizedDirectory, loader, elements); if (dex != null) { elements[elementsPos++] = new Element(dex, null); } } } ... 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); } } 
4.这里通过 new DexFile 或者 loadDex方法来创建DexFile,两者类似,那我们拿new DexFile 来举例分析
//DexFile.java
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
   DexPathList.Element[] elements) throws IOException {
  ...
  //此处调用openDexFile来实现
  mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
  ...
 }
private static Object openDexFile(String sourceName, String outputName, int flags,
   ClassLoader loader, DexPathList.Element[] elements) throws IOException {
  //此处通过调用 openDexFileNative来实现
  return openDexFileNative(new File(sourceName).getAbsolutePath(),
         (outputName == null)
          ? null
          : new File(outputName).getAbsolutePath(),
         flags,
         loader,
         elements);
 }
//openDexFileNative是一个native方法,是由C/C++来实现的
private static native Object openDexFileNative(String sourceName, String outputName, int flags,
   ClassLoader loader, DexPathList.Element[] elements);感谢你能够认真阅读完这篇文章,希望小编分享的“ClassLoader类加载的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!
网页题目:ClassLoader类加载的示例分析
文章分享:http://www.scyingshan.cn/article/ighsch.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 