类加载器的作用:
- 类加载,
通过类的权限定名获取此类的二进制字节流
- 确定被加载的类在jvm中的唯一性
两个类是否相等的依据:是否由同一个ClassLoader加载
两个类是否相等的判断:
- equals
- isAssignableFrom
- isInstance
类加载器的类型:
- 启动类加载器(Bootstrap ClassLoader)
- 用于加载存放在
<JAVA_HOME>\lib
目录下和被-Xbootclasspath
参数指定的类(事先定义好的类) - 仅按文件名识别,如:rt.jar,名字不符合的类库即使放在lib目录中也不会被加载
- 无法被java程序直接使用
- 扩展类加载器(Extension ClassLoader)
- 加载
JAVA_HOME>\lib\ext
目录中和被java.ext.dirs
系统变量所指定的路径中的类 - 开发者可以直接使用扩展类加载器
- 应用程序类加载器
- 负责加载 用户类路径
(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;
}
加载流程:
- 当一个加载器收到加载请求需求时,会提交给他的父类加载器去完成
- 只有当父类加载器反馈无法加载时,自己才会去加载
优点:
类加载器的层级关系保证了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<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
return null;
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> 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<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
dexFile.loadClassBinaryName()是一个native方法

网友评论