[Android Interview Questions] The latest interview topic in 2023: Java reflection class loading and dynamic proxy (1)

1 What is the difference between PathClassLoader and DexClassLoader?

What is this question trying to investigate?

The principle of class loading mechanism in Android

Knowledge points of inspection

ClassLoader class loading mechanism

How Candidates Answer

ClassLoader is what we often call a class loader.

Introduction to ClassLoader

Any Java program is composed of one or more class files. When the program is running, the class files need to be loaded into the JVM before they can be used. The Java class loading mechanism is responsible for loading these class files. The role of ClassLoader is simply to load class files and provide them for use when the program is running. There is a classLoader field inside each Class object to identify which ClassLoader it is loaded by.

class Class<T> {
    
    
  ...
  private transient ClassLoader classLoader;
  ...
}

ClassLoader is an abstract class, and it has many concrete implementation classes, the most important ones are:

  • BootClassLoader

    Used to load Android Framework layer class files.

  • PathClassLoader

    For Android application classloaders. Can load specified dex, and classes.dex in jar, zip, apk

  • DexClassLoader

    Used to load the specified dex, and classes.dex in jar, zip, apk

  • InMemoryDexClassLoader

    Added in Android 8.0, used to load dex in memory

DexClassLoader and PathClassLoader

In versions below Android 5.0, the difference between the two is:

  1. DexClassLoader: jar, apk and dex can be loaded, and can be loaded from SD card
  2. PathClassLoader : can only load apk files that have been installed in the system (that is, in the /data/app directory)

But with the upgrade of the Android version, this is no longer the case for Android 5.0 and beyond.

PathClassLoaderLet's first look at the and in 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);
    }
}

PathClassLoaderBoth of them DexClassLoaderinherit from the same parent class: BaseDexClassLoader, and the difference between the two is that DexClassLoaderan optimizedDirectory must be passed to store the result of dexopt, while the latter does not.

dexopt:

In Dalvik , when the virtual machine loads a dex file, it verifies and optimizes the dex file, and the optimization result of the dex file becomes an odex (Optimized dex) file, which uses some optimized opcodes, and dex Documentation is similar.

In fact, whether it is PathClassLoaderor not DexClassLoader, you can see that there are no other methods of overriding the parent class. If the optimizedDirectory optimization directory is Null, that is PathClassLoader, below Android5.0, the default optimized directory will be used: /data/dalvik-cache/ .

When installing an APK in this directory, the system will automatically store odex files in it: data@[email protected]@classes.dex
insert image description here

When using PathClassLoaderloading, if the loaded APK is not already installed in the mobile phone, it will report: Dex cache directory isn't writable: /data/dalvik-cache , our application itself does not have write permission for this directory . So PathClassLoader can only load the dex files in the installed APK.

Under ART, the loading method has undergone a completely different change. During installation, dex2oat (AOT ahead of time compilation operation) is executed on the dex file, and compiled into an OAT (actually an ELF file) executable file (machine code). And if the oat file cannot be successfully loaded during loading, it will still try to load from the original dex. Therefore, under ART, you PathClassLoadercan DexClassLoaderload any specified dex, as well as classes.dex in jar, zip, and apk. However, loading from the original dex will result in the failure of dex2oat, which will speed up the loading and reduce the operating efficiency.

After Android N, interpretation, AOT and JIT mixed mode are adopted.

On Android 8.1 and later, DexClassLoaderit becomes:

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}

At this time, optimizedDirectory in DexClassLoader is also fixed to pass null, so there is no difference between the two.

Summarize

  • Android 4.4 and below:
    • DexClassLoader: jar, apk and dex can be loaded, and can be loaded from SD card
    • PathClassLoader : can only load apk files that have been installed in the system (that is, in the /data/app directory)
  • Android 5.0~Android 8.0:
    • DexClassLoader: jar, apk and dex can be loaded, and can be loaded from SD card
    • PathClassLoader: jar, apk and dex can be loaded, and can be loaded from the SD card, but it will make it impossible to perform dex2oat operation
  • Android 8.1 and above:
    • DexClassLoader is exactly the same as PathClassLoader

2 What is the parental entrustment mechanism, and why is the parental entrustment mechanism needed?

What is this question trying to investigate?

Principle of class loading mechanism

Knowledge points of inspection

class loading mechanism

How Candidates Answer

Parental Delegation Mechanism

The parent delegation mechanism means that when a class loader receives a class loading request, the class loader will first delegate the request to the parent class loader. The same is true for each class loader. Only when the parent class loader cannot find the specified class within its own search range, the child class loader will try to load it by itself.

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;
    }
}

The Role of the Parental Delegation Mechanism

1. Prevent duplicate loading

2. Security, to ensure that the system class cannot be tampered with.

The Java virtual machine will only determine that this is a class when the class names of different classes are the same and the loaders that load the class are all the same. If there is no parent delegation mechanism, the same class may be loaded by multiple class loaders, so the class may be recognized as two different classes, and problems will arise when assigning values ​​to each other.

The parental delegation mechanism can ensure that when multiple loaders load a class, it will be loaded by one loader in the end, ensuring that the final loading results are the same.

There is no parental delegation model, if all class loaders are allowed to load by themselves, if the user writes a class called java. The basic behavior in the type system cannot be guaranteed, and the application will become a mess.

3 What are the methods of loading classes in Android? What's the difference?

What is this question trying to investigate?

The process of class loading in the class loading mechanism

Knowledge points of inspection

  1. class loading process
  2. class loading time

How should candidates answer

The way Android loads classes is actually Java's class loading. The virtual machine loads the information describing the class from the Class file to the memory, and verifies, converts, parses, and initializes the data, and finally becomes a Java type that can be directly used by the virtual machine.

class loading time

Classes are automatically loaded when:

  1. Using new to instantiate an object, creating an instance of a subclass will first load its parent class
  2. Access to static methods of a class
  3. Access to static properties of a class
  4. Make reflective calls to classes
  5. The main class is defined in the Java program, and the class will be loaded when the main method is started

The above five situations will trigger the loading of the class and complete the initialization of the class. In addition to the above situations, we can also actively call ClassLoader#loadClass(name)or Class.forName(name)load. In fact, Class.forName(name)the loading of the specified class is also completed through 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);
}

But ClassLoader#loadClass(name)the Class.forName(name) difference is that in addition to completing class loading, the latter also initializes the class and executes the static block in the class. Instead, ClassLoader#loadClassonly class loading is done.

Of course, we can also use: Class.forName(String name, boolean initialize, ClassLoader loader). Through the second parameter initialize, you can choose whether to initialize the class.

at last

This interview question will continue to be updated, please pay attention! ! ! !
Friends who need this interview question can scan the QR code below to get it for free! ! !
At the same time, by scanning the QR code below, you can also enter the group to enjoy the service of the ChatGPT robot! ! !

Guess you like

Origin blog.csdn.net/datian1234/article/details/131987451