android中的类加载器
来源:互联网 发布:简述数据库系统的特点 编辑:程序博客网 时间:2024/05/29 18:42
android的类加载机制跟Java类似,也是采用“双亲委托”机制。即用户在用自己定义的类加载器加载类时,会首先尝试调用该加载器的父加载器来进行加载,加载不成功再返回给子加载器来加载。同样,该父类加载器在加载时也会调用其父类加载器进行加载,也就是原加载器的爷爷加载器进行加载,不成功再往下返回。一层层往上调用,直到到达“引导加载器”,这个加载器是Dalvik实现的一部分,是用C而非用Java实现的,因为类加载器也是类,使用前也要进行加载,这就要求有一个加载器来实现类加载器的加载。这个流程可以从ClassLoader类的loadClass()方法看出来:
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { try { clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. } if (clazz == null) { clazz = findClass(className); } } return clazz;}
如上述代码所示,在调用loadClass加载类时,会首先判断该类是否已经被加载,如果该类已经被加载则返回此类,否则会调用父类加载器来尝试加载。如果父类加载器无法加载,则会返回给子加载器来加载(findClass)。为什么会出现加载器无法加载的情况呢,是因为这些加载器类(引导加载器、系统加载器等)都有自己的“命名空间”,加载器在进行类加载时会从固定目录中尝试类加载,如果在这些目录中无法找到想加载的类加载就会失败。下面通过一个动态加载类的例子来捋一下流程:
String path = Environment.getExternalStorageDirectory() + "/";File file = getDir("dex", 0) ;String filename = "TestB.apk";classLoader = new DexClassLoader(path + filename, file.getAbsolutePath(),null, ClassLoader.getSystemClassLoader());Application app = classLoader.loadClass(strClassName).newInstance();
上述classLoader是DexClassLoader对象,loadClass返回一个被加载的类的Class对象,我们来分析一下loadClass到底是如何加载一个类的。DexClassLoader继承自BaseClassLoader,在DexClassLoader中并没有loadClass的实现,因为DexClassLoader继承自BaseClassLoader,BaseClassLoader又继承自ClassLoader,所以在加载时是调用了ClassLoader的loadClass。从上面代码中可以知道,loadClass其实是调用findClass来实现类的加载。因为被加载的类不在父类加载器的“命名空间”内,所以最后还是要调用DexClassLoader的findClass来实现类的加载。下面我们就来看一下findClass是如何实现类加载的。
protected Class<?> findClass(String name) throws ClassNotFoundException { Class c = pathList.findClass(name); if (c == null) { throw new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList); } return c;}
其中pathList为DexPathList对象,即调用DexPathList的findclass,所以我们需要继续跳转到DexPathList中来看findClass是如何实现的。(跟踪代码确实很麻烦)
public Class findClass(String name) { for (Element element : dexElements) { DexFile dex = element.dexFile; if (dex != null) { Class clazz = dex.loadClassBinaryName(name, definingContext); if (clazz != null) { return clazz; } } } return null;}
其中,dex是DexFile对象,在这里我们来看一下DexFile类长啥样,DexFile也是在类加载中比较底层的起重要作用的类。
public final class DexFile { private int mCookie; private final String mFileName; private final CloseGuard guard = CloseGuard.get(); public DexFile(String fileName) throws IOException { mCookie = openDexFile(fileName, null, 0); mFileName = fileName; guard.open("close"); }}
在DexFile中有几个native方法,比较重要的两个是openDexFile、defineClass。openDexFile返回值类型为int(在DexFile的构造中将此返回值传给mCookie),源码中是这样注释的:A pointer to our internal data structure,即dex文件被加载之后的内存地址。而private static Class defineClass(String name, ClassLoader loader, int cookie)的注释是:Load a class from a DEX file,参数cookie就是openDexFile的返回值,而name是要加载的类。总的来说,可以这么理解:先用openDexFile将dex文件读到一个特殊的数据结构中(支持从硬盘或者内存中读取),然后用defineClass实现某一个类的加载。
- android中的类加载器
- android中的类加载器
- Android中的类加载器
- android中的类加载器,以及加载机制
- AsyncLoader - Android中的异步加载器
- Android 加载其他Apk中的类方法
- Android中的异步加载
- android中的异步加载
- Android中的图片加载
- Android中的动态加载
- Android类加载器
- Tomcat中的类加载器
- Java中的类加载器
- java中的类加载器
- Java中的类加载器
- java中的类加载器
- Java中的类加载器
- Java中的类加载器
- Oracle AWR 介绍
- _stprintf_s和_stscanf_s
- C#中使用byte[]数据,生成Bitmap
- UVa 572 Oil Deposits(DFS求8连通块)
- Android设备无法查看logcat解决方法
- android中的类加载器
- Lambda表达式
- android运行apk停止运行---dalvik vm兼容性问题
- tomcat多域名配置
- Ajax传参中文问题
- linux的系统目录
- javascript 为元素绑定事件并获取元素位置
- 分析归档日志提取某些对象被修改的记录
- CocoaPods安装和使用教程