1 ¿Cuál es la diferencia entre PathClassLoader y DexClassLoader?
¿Qué está tratando de investigar esta pregunta?
El principio del mecanismo de carga de clases en Android
Puntos de conocimiento de inspección
Mecanismo de carga de clases ClassLoader
Cómo responden los candidatos
ClassLoader es lo que solemos llamar un cargador de clases.
Introducción a ClassLoader
Cualquier programa Java se compone de uno o más archivos de clase. Cuando el programa se está ejecutando, los archivos de clase deben cargarse en la JVM antes de que puedan usarse. El mecanismo de carga de clases de Java es responsable de cargar estos archivos de clase. La función de ClassLoader es simplemente cargar archivos de clase y proporcionarlos para su uso cuando el programa se está ejecutando. Hay un campo classLoader dentro de cada objeto Class para identificar qué ClassLoader lo carga.
class Class<T> {
...
private transient ClassLoader classLoader;
...
}
ClassLoader es una clase abstracta y tiene muchas clases de implementación concretas, las más importantes son:
-
BootClassLoader
Se utiliza para cargar archivos de clase de capa de Android Framework.
-
PathClassLoader
Para cargadores de clases de aplicaciones de Android. Puede cargar dex especificado y classes.dex en jar, zip, apk
-
DexClassLoader
Se usa para cargar el dex especificado y las clases.dex en jar, zip, apk
-
InMemoryDexClassLoader
Agregado en Android 8.0, usado para cargar dex en la memoria
DexClassLoader y PathClassLoader
En versiones anteriores a Android 5.0, la diferencia entre los dos es:
- DexClassLoader: se pueden cargar jar, apk y dex, y se pueden cargar desde la tarjeta SD
- PathClassLoader: solo puede cargar archivos apk que se hayan instalado en el sistema (es decir, en el directorio /data/app)
Pero con la actualización de la versión de Android, este ya no es el caso para Android 5.0 y posteriores.
PathClassLoader
Veamos primero el y en Android 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);
}
}
Ambos heredan de la misma clase principal: , y la diferencia entre los dos es que se debe pasar un directorio optimizadoPathClassLoader
para almacenar el resultado de dexopt, mientras que el último no.DexClassLoader
BaseDexClassLoader
DexClassLoader
dexopto:
En Dalvik , cuando la máquina virtual carga un archivo dex, verifica y optimiza el archivo dex, y el resultado de la optimización del archivo dex se convierte en un archivo odex (dex optimizado), que usa algunos códigos de operación optimizados, y la documentación de dex es similar.
De hecho, ya sea que lo sea PathClassLoader
o no DexClassLoader
, puede ver que no hay otros métodos para anular la clase principal. Si el directorio de optimización deOptimizedDirectory es nulo, es decir PathClassLoader
, por debajo de Android5.0, se usará el directorio optimizado predeterminado: /data/dalvik-cache/ .
Al instalar un APK en este directorio, el sistema almacenará automáticamente archivos odex en él: data@[email protected]@classes.dex
Al usar PathClassLoader
la carga, si el APK cargado aún no está instalado en el teléfono móvil, informará: El directorio de caché de Dex no se puede escribir: /data/dalvik-cache , nuestra aplicación en sí no tiene permiso de escritura para este directorio. Entonces PathClassLoader solo puede cargar los archivos dex en el APK instalado.
Bajo ART, el método de carga ha sufrido un cambio completamente diferente. Durante la instalación, dex2oat (operación de compilación anticipada de AOT) se ejecuta en el archivo dex y se compila en un archivo ejecutable OAT (en realidad, un archivo ELF) (código de máquina). Y si el archivo Oat no se puede cargar con éxito durante la carga, aún intentará cargar desde el dex original. Por lo tanto, en ART, puede cargar PathClassLoader
cualquier DexClassLoader
dex especificado, así como también classes.dex en jar, zip y apk. Sin embargo, la carga desde el dex original provocará la falla de dex2oat, lo que acelerará la carga y reducirá la eficiencia operativa.
Después de Android N, se adoptan la interpretación, el modo mixto AOT y JIT .
En Android 8.1 y versiones posteriores, DexClassLoader
se convierte en:
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}
En este momento, el directorio optimizado en DexClassLoader también está arreglado para pasar nulo, por lo que no hay diferencia entre los dos.
Resumir
- Android 4.4 y anteriores:
- DexClassLoader: se pueden cargar jar, apk y dex, y se pueden cargar desde la tarjeta SD
- PathClassLoader: solo puede cargar archivos apk que se hayan instalado en el sistema (es decir, en el directorio /data/app)
- Android 5,0 ~ Android 8,0:
- DexClassLoader: se pueden cargar jar, apk y dex, y se pueden cargar desde la tarjeta SD
- PathClassLoader: se pueden cargar jar, apk y dex, y se pueden cargar desde la tarjeta SD, pero hará que sea imposible realizar la operación dex2oat
- Android 8.1 y superior:
- DexClassLoader es exactamente lo mismo que PathClassLoader
2 ¿Qué es el mecanismo de encomienda de los padres y por qué es necesario el mecanismo de encomienda de los padres?
¿Qué está tratando de investigar esta pregunta?
Principio del mecanismo de carga de clases
Puntos de conocimiento de inspección
mecanismo de carga de clases
Cómo responden los candidatos
Mecanismo de Delegación de Padres
El mecanismo de delegación principal significa que cuando un cargador de clases recibe una solicitud de carga de clases, el cargador de clases primero delegará la solicitud al cargador de clases principal. Lo mismo es cierto para cada cargador de clases. Solo cuando el cargador de clases principal no puede encontrar la clase especificada dentro de su propio rango de búsqueda, el cargador de clases secundario intentará cargarla por sí mismo.
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;
}
}
El papel del mecanismo de delegación de padres
1. Evite la carga duplicada
2. Seguridad, para garantizar que la clase del sistema no pueda ser alterada.
La máquina virtual de Java solo determinará que se trata de una clase cuando los nombres de las diferentes clases sean los mismos y los cargadores que cargan la clase sean todos iguales. Si no hay un mecanismo de delegación principal, varios cargadores de clases pueden cargar la misma clase, por lo que la clase puede reconocerse como dos clases diferentes y surgirán problemas al asignar valores entre sí.
El mecanismo de delegación de padres puede garantizar que cuando varios cargadores carguen una clase, al final será cargada por un cargador, asegurando que los resultados finales de la carga sean los mismos.
No existe un modelo de delegación parental, si se permite que todos los cargadores de clases se carguen solos, si el usuario escribe una clase llamada java, no se puede garantizar el comportamiento básico en el sistema de tipos y la aplicación se convertirá en un desastre.
3 ¿Cuáles son los métodos de carga de clases en Android? ¿Cual es la diferencia?
¿Qué está tratando de investigar esta pregunta?
El proceso de carga de clases en el mecanismo de carga de clases
Puntos de conocimiento de inspección
- proceso de carga de clases
- tiempo de carga de la clase
¿Cómo deben responder los candidatos?
La forma en que Android carga las clases es en realidad la carga de clases de Java. La máquina virtual carga la información que describe la clase desde el archivo Class a la memoria, y verifica, convierte, analiza e inicializa los datos, y finalmente se convierte en un tipo Java que la máquina virtual puede usar directamente.
tiempo de carga de la clase
Las clases se cargan automáticamente cuando:
- Usando new para instanciar un objeto, crear una instancia de una subclase primero cargará su clase principal
- Acceso a métodos estáticos de una clase.
- Acceso a las propiedades estáticas de una clase
- Hacer llamadas reflexivas a las clases
- La clase principal se define en el programa Java y la clase se cargará cuando se inicie el método principal.
Las cinco situaciones anteriores activarán la carga de la clase y completarán la inicialización de la clase. Además de las situaciones anteriores, también podemos llamar ClassLoader#loadClass(name)
o Class.forName(name)
cargar activamente. De hecho, Class.forName(name)
la carga de la clase especificada también se completa a través de ClassLoader.
public static Class<?> forName(String className) throws ClassNotFoundException {
//得到调用者的类,如main方法所在类
Class<?> caller = Reflection.getCallerClass();
//ClassLoader.getClassLoader(caller):获得main方法所在类的类加载器,使用其完成className的加载
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
Pero ClassLoader#loadClass(name)
la Class.forName(name)
diferencia es que además de completar la carga de clases, este último también inicializa la clase y ejecuta el bloque estático en la clase. En cambio, ClassLoader#loadClass
solo se realiza la carga de clases.
Por supuesto, también podemos usar: Class.forName(String name, boolean initialize, ClassLoader loader)
. A través del segundo parámetro initialize, puede elegir si inicializar la clase.
por fin
Esta pregunta de la entrevista continuará actualizándose, ¡preste atención! ! ! !
¡Los amigos que necesiten esta pregunta de entrevista pueden escanear el código QR a continuación para obtenerla gratis! ! !
¡Al mismo tiempo, al escanear el código QR a continuación, también puede ingresar al grupo para disfrutar del servicio del robot ChatGPT! ! !