Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊 👀你想要的面试题这里都有👀 👇👇👇
PathClassLoader与DexClassLoader的区别是什么?
这道题想考察什么?
Android中类加载机制的原理
考察的知识点
ClassLoader类加载机制
考生如何回答
ClassLoader就是我们常说的类加载器。
ClassLoader简介
任何一个 Java 程序都是由一个或多个 class 文件组成,在程序运行时,需要将 class 文件加载到 JVM 中才可以使用,负责加载这些 class 文件的就是 Java 的类加载机制。ClassLoader 的作用简单来说就是加载 class 文件,提供给程序运行时使用。每个 Class 对象的内部都有一个 classLoader 字段来标识自己是由哪个 ClassLoader 加载的。
class Class<T> {
...
private transient ClassLoader classLoader;
...
}
ClassLoader是一个抽象类,而它的具体实现类很多,最为主要被使用的有:
-
BootClassLoader用于加载Android Framework层class文件。
-
PathClassLoader用于Android应用程序类加载器。可以加载指定的dex,以及jar、zip、apk中的classes.dex
-
DexClassLoader用于加载指定的dex,以及jar、zip、apk中的classes.dex
-
InMemoryDexClassLoaderAndroid8.0新增,用于加载内存中的dex
DexClassLoader与PathClassLoader
在Android 5.0以下的版本中,两者之间的区别为:
- DexClassLoader : 可加载jar、apk和dex,可以从SD卡中加载
- PathClassLoader : 只能加载已安裝到系統中(即/data/app目录下)的apk文件
但是随着Android版本的升级,到Android 5.0及以后就已经不是这样了。
我们先来看看在Android 中的PathClassLoader与DexClassLoader:
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
}
其中PathClassLoader与DexClassLoader都是继承自同一个父类:BaseDexClassLoader,而两者的区别则是DexClassLoader必须传递一个optimizedDirectory 用于存放dexopt的结果,后者则不用。
dexopt:
在Dalvik中虚拟机在加载一个dex文件时,对 dex 文件 进行 验证 和 优化的操作,其对 dex 文件的优化结果变成了 odex(Optimized dex) 文件,这个文件使用了一些优化操作码,和 dex 文件很像。
其实无论是PathClassLoader还是DexClassLoader,大家可以看到并没有重写父类的其他方法。如果optimizedDirectory 优化目录为Null,即PathClassLoader,则Android5.0以下,则会使用默认的优化目录: /data/dalvik-cache/ 。
而这个目录在安装某个APK时,系统会自动在其中存放odex文件:
而在使用PathClassLoader加载时,如果加载的不是已经安装在手机中的APK,则会报出:Dex cache directory isn't writable: /data/dalvik-cache,这个目录我们的应用自身并不具备写的权限。因此PathClassLoader只能加载已经安装的APK中的dex文件。
而到了ART下,加载方式发生了截然不同的变化,在安装时对 dex 文件执行dex2oat(AOT 提前编译操作),编译为OAT(实际上是ELF文件)可执行文件(机器码)。而如果在加载时,无法成功加载oat文件,仍然会尝试从原dex中加载,因此ART下,PathClassLoader与DexClassLoader都能加载任意指定的dex,以及jar、zip、apk中的classes.dex。但是从原dex加载会导致无法dex2oat,加快加载速度,降低运行效率。
到了Android N之后采用解释,AOT与JIT 混合模式。
到了Android 8.1及以后,DexClassLoader变为:
public class DexClassLoader extends BaseDexClassLoader {
35 /**
36 * Creates a {@code DexClassLoader} that finds interpreted and native
37 * code. Interpreted classes are found in a set of DEX files contained
38 * in Jar or APK files.
39 *
40 * <p>The path lists are separated using the character specified by the
41 * {@code path.separator} system property, which defaults to {@code :}.
42 *
43 * @param dexPath the list of jar/apk files containing classes and
44 * resources, delimited by {@code File.pathSeparator}, which
45 * defaults to {@code ":"} on Android
46 * @param optimizedDirectory this parameter is deprecated and has no effect
47 * @param librarySearchPath the list of directories containing native
48 * libraries, delimited by {@code File.pathSeparator}; may be
49 * {@code null}
50 * @param parent the parent class loader
51 */
52 public DexClassLoader(String dexPath, String optimizedDirectory,
53 String librarySearchPath, ClassLoader parent) {
54 super(dexPath, null, librarySearchPath, parent);
55 }
56}
此时DexClassLoader中optimizedDirectory同样固定传递null,因此两者没有任何区别了。
总结
-
Android 4.4及以下:
- DexClassLoader : 可加载jar、apk和dex,可以从SD卡中加载
- PathClassLoader : 只能加载已安裝到系統中(即/data/app目录下)的apk文件
-
Android 5.0~Android 8.0:
- DexClassLoader : 可加载jar、apk和dex,可以从SD卡中加载
- PathClassLoader : 可加载jar、apk和dex,可以从SD卡中加载,但会导致无法进行dex2oat操作
-
Android 8.1及以上:
- DexClassLoader 与 PathClassLoader 完全一致
什么是双亲委托机制,为什么需要双亲委托机制?
这道题想考察什么?
类加载机制原理
考察的知识点
类加载机制
考生如何回答
双亲委托机制
双亲委托机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。
public abstract class ClassLoader{
//父类加载器
ClassLoader parent;
protected ClassLoader(ClassLoader parentLoader) {
this(parentLoader, false);
}
ClassLoader(ClassLoader parentLoader, boolean nullAllowed) {
if (parentLoader == null && !nullAllowed) {
throw new NullPointerException("parentLoader == null && !nullAllowed");
}
parent = parentLoader;
}
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
//先找缓存
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
if(parent !=null){
try {
//交给父类加载器加载
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
suppressed = e;
}
}
if (clazz == null) {
try {
//父类加载器加载不到,自己加载
clazz = findClass(className);
} catch (ClassNotFoundException e) {
e.addSuppressed(suppressed);
throw e;
}
}
}
return clazz;
}
}
双亲委托机制的作用
1、防止重复加载
2、安全,保证系统类不能被篡改。
Java虚拟机只会在不同的类的类名相同且加载该类的加载器均相同的情况下才会判定这是一个类。如果没有双亲委派机制,同一个类可能就会被多个类加载器加载,如此类就可能会被识别为两个不同的类,相互赋值时问题就会出现。
双亲委派机制能够保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。
没有双亲委派模型,让所有类加载器自行加载的话,假如用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,系统就会出现多个不同的Object类, Java类型体系中基础行为就无法保证,应用程序就会变得一片混乱。
更多Android面试题 可以详细Vx关注公众号:Android老皮 解锁 《2023最新Android中高级面试题汇总+解析》
第一章 Java方面
- Java基础部分
- Java集合
- Java多线程
- Java虚拟机
第二章 Android方面
- Android四大组件相关
- Android异步任务和消息机制
- Android UI绘制相关
- Android性能调优相关
- Android中的IPC
- Android系统SDK相关
- 第三方框架分析
- 综合技术
- 数据结构方面
- 设计模式
- 计算机网络方面
- Kotlin方面
第三章 音视频开发高频面试题
- 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
- 怎么做到直播秒开优化?
- 直方图在图像处理里面最重要的作用是什么?
- 数字图像滤波有哪些方法?
- 图像可以提取的特征有哪些?
- 衡量图像重建好坏的标准有哪些?怎样计算?
第四章 Flutter高频面试题
- Dart部分
- Flutter部分
第五章 算法高频面试题
- 如何高效寻找素数
- 如何运用二分查找算法
- 如何高效解决雨水问题
- 如何去除有序数组的重复元素
- 如何高效进行模幂运算
- 如何寻找最长回文子串
第六章 Andrio Framework方面
- 系统启动流程面试题解析
- Binder面试题解析
- Handler面试题解析
- AMS面试题解析