Android Class类加载机制
来源:互联网 发布:2017淘宝违禁词有哪些 编辑:程序博客网 时间:2024/06/06 02:15
1 前言
Class类加载机制是了解Android高级技术的基础,现在热门的热修复,插件化,以及Dex分包等技术,都需要理解class类加载机制,了解了class类加载机制我们能更好的理解Android内部原理,从而使我们的技术提高一个层次
Android是基于java的,我们先来了解一下java的类加载机制
2 java Class类加载机制
java系统自带有三个类加载器,分别是Bootstrap ClassLoader, Extention ClassLoader,Appclass Loader
Bootstrap ClassLoader :是用C++语言实现的,最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。
Extention ClassLoader :扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
Appclass Loader:也称为SystemAppClass 加载当前应用的classpath的所有类。
加载顺序
1. Bootstrap CLassloder
2. Extention ClassLoader
3. AppClassLoader
在java代码中我们可以使用如下代码进行测试:
ClassLoader classLoader = Main.class.getClassLoader();//是APPClassLoaderSystem.out.println("Main.class ClassLoader:" + classLoader.toString());URL[] urls = ((URLClassLoader)classLoader).getURLs();printURL(urls);ClassLoader parent1 = classLoader.getParent();//是ExtClassLoaderSystem.out.println("Main.class parent ClassLoader:" + parent1.toString());URL[] urls2 = ((URLClassLoader)parent1).getURLs();printURL(urls2);ClassLoader parent2 = parent1.getParent();//是BootstrapLoaderSystem.out.println("ExtClassLoader parent ClassLoader:" + parent2.toString());
这三者的关系如下:
这三者的继承关系如下:
3 Android Class类加载机制
在Android中 有 2种类加载器:
PathClassLoader和DexClassLoader。分别位于如下
libcore\dalvik\src\main\java\dalvik\system\PathClassLoader.java
libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java
定义如下
/** * Provides a simple {@link ClassLoader} implementation that operates on a list * of files and directories in the local file system, but does not attempt to * load classes from the network. Android uses this class for its system class * loader and for its application class loader(s). */public class **PathClassLoader** extends BaseDexClassLoader { ......}/** * A class loader that loads classes from {@code .jar} and {@code .apk} files * containing a {@code classes.dex} entry. This can be used to execute code not * installed as part of an application. * * <p>This class loader requires an application-private, writable directory to * cache optimized classes. Use {@code Context.getCodeCacheDir()} to create * such a directory: <pre> {@code * File dexOutputDir = context.getCodeCacheDir(); * }</pre> * * <p><strong>Do not cache optimized classes on external storage.</strong> * External storage does not provide access controls necessary to protect your * application from code injection attacks. */public class **DexClassLoader** extends BaseDexClassLoader { ......}
可以看到都继承了BaseDexClassLoader 这个基类,这个类又是继承ClassLoader的,这里先不去管它。我们来看注释。
对于PathClassLoader,从文档上的注释来看:Android是使用这个类作为其系统类和应用类的加载器。并且对于这个类呢,只能去加载已经安装到Android系统中的apk文件。
对于DexClassLoader,依然看下注释:可以看到可以加载从jar包中的,apk中的类。
Android要加载一个类 是通过ClassLoader的findClass方法 在dex中查找这个类 找到后加载到内存
我们来看下Android中类是如何加载的。
我们查看PathClassLoader与DexClassLoader均发现没有findClass()方法,因此我们在其父类BaseDexClassLoader中找一下
/** * Base class for common functionality between various dex-based * {@link ClassLoader} implementations. */public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; ... @Override protected Class<?> findClass(String name) throws ClassNotFoundException { List<Throwable> suppressedExceptions = new ArrayList<Throwable>(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; } ....}
可以看到,Android中类的加载是从DexPathList 的findClass()方法中加载的,我们再来看DexPathList 中查看
final class DexPathList { private static final String DEX_SUFFIX = ".dex"; ...... /** * List of dex/resource (class path) elements. * Should be called pathElements, but the Facebook app uses reflection * to modify 'dexElements' (http://b/7726934). */ private final Element[] dexElements; ...... /** * Finds the named class in one of the dex files pointed at by * this instance. This will find the one in the earliest listed * path element. If the class is found but has not yet been * defined, then this method will define it in the defining * context that this instance was constructed with. * * @param name of class to find * @param suppressed exceptions encountered whilst finding the class * @return the named class or {@code null} if the class is not * found in any of the dex files */ public Class findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { DexFile dex = element.dexFile; if (dex != null) { Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); if (clazz != null) { return clazz; } } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; }}
可以看到查找类是在dexElements数组中依次遍历查找的。一个classloader可以包含多个dex,其中这个集合中的对象就是所有的dex文件,查找是从头开始遍历所有的dex 如果在dex中找到所需要的类,那么就直接返回。
在这个dex中查找相应名字的类,之后 defineClass把字节码交给虚拟机就完成了类的加载。
- Android Class类加载机制
- jvm加载class类机制
- Class类文件加载机制
- Class类文件加载机制
- Class类文件加载机制
- java加载class文件(类加载机制)
- Android Class加载机制(未完)
- Android中的class动态加载机制
- 类加载机制及类加载器加载Class流程
- 类加载机制之Class.forName()
- java 虚拟机类Class加载机制
- java 类加载机制-class生命周期
- JVM class加载机制
- jvm-class加载机制
- Android类加载机制学习
- JVM类加载机制浅析 (How ClassLoader load class file )
- Java类加载机制 .class文件加载 .class文件实例化对象 Spring自动包扫描Bean原理
- JVM 加载 class 文件的原理机制(类的生命周期、类加载器)
- Elasticsearch-前缀、通配符、正则、模糊搜索详解
- TCP 粘包问题
- RTMP 直播推流时延
- 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 C. Sum
- OpenJudge百炼-1936-全在其中-C语言-字符串处理
- Android Class类加载机制
- MYSQL简单的binlog恢复测试
- 海量数据处理的SQL性能优化
- 交叉表查询
- Selenium+Python 自动化操控登录界面(有简单验证码图片校验)
- .NET编程(02) 反射
- Git高级教程- 远程仓库版本回退方法
- 小工具-jsp实现验证码功能
- Leetcode-Pointer Magic