Java高級---類加載ClassLoader

任何一個java程序都是有一個或多個class文件組成的,在程序運行時,需要將class文件加載到JVM虛擬機中才可以用,負責加載這些class文件的就是java的類加載機制。

簡單來說:就是加載class文件,提供給程序運行時使用。

知識點

1)基本職責就是根據一個指定的類的名稱,找到或者生成其對應的字節(jié)碼,然后從這些字節(jié)碼代碼中定義出一個java類的實例。

2)工作原理則是通過雙親委托機制來實現的,這也可以避免重復加載,保證類的唯一性,且java類隨著他的類加載器一起具備了一種帶有優(yōu)先級的層次關系。

? 如何保證類的唯一性呢?

JVM在判斷兩個class是否相同時,不僅僅要判斷兩個類名是否相同,還要判斷負責加載這兩個類的加載器是否一樣,也就是說同一個類加載器加載相同名稱的類,虛擬機才會認為加載的是同一個類,否則的話認為他們是不同的類。

ClassLoader是一個抽象類,他在android中的具體實現類有:

**1. BootClassLoader:**        用于加載android Framework層的class文件

**2. PathClassLoader:**        用于加載android 應用程序中的類加載器,可以是指定的dex,jar,  zip ,  apk中的class.dex

**3. DexClassLoader:**         用于加載指定的dex ,jar ,zip ,apk中的classes.dex
類加載器類圖

了解上面的一些基礎概念理論的東西后,我們用一張流程圖來分析一下類加載器的工作原理:


類加載的工作原理流程圖

知識點:

類加載的雙親委托機制

? 類加載器在嘗試自己去查找某一個類的字節(jié)碼時,會先就這個任務交給他的父類加載器去嘗試加載這個類,而父類加載器也先交給父類的父類加載器去執(zhí)行,依次遞歸查找。如果父類找到了則直接返回,如果父類沒有找到則再由類加載器自己查找,這種查找的方式就是雙親委托機制。

剖析源碼

? 解析來我們來從源碼角度一步一步潛入類加載器中學習一下,其他類加載器的幾個類都比較簡單,相對復雜的是在ClassLoader.java中。廢話不多說,直接開擼。。。。。。。

  1. BaseDexClassLoader.java

public class BaseDexClassLoader extends ClassLoader {
32
33    /**
34     * Hook for customizing how dex files loads are reported.
35     *
36     * This enables the framework to monitor the use of dex files. The
37     * goal is to simplify the mechanism for optimizing foreign dex files and
38     * enable further optimizations of secondary dex files.
39     *
40     * The reporting happens only when new instances of BaseDexClassLoader
41     * are constructed and will be active only after this field is set with
42     * {@link BaseDexClassLoader#setReporter}.
43     */
44    /* @NonNull */ private static volatile Reporter reporter = null;
45
46    private final DexPathList pathList;
47
48    /**
49     * Constructs an instance.
50     * Note that all the *.jar and *.apk files from {@code dexPath} might be
51     * first extracted in-memory before the code is loaded. This can be avoided
52     * by passing raw dex files (*.dex) in the {@code dexPath}.
53     *
54     * @param dexPath the list of jar/apk files containing classes and
55     * resources, delimited by {@code File.pathSeparator}, which
56     * defaults to {@code ":"} on Android.
57     * @param optimizedDirectory this parameter is deprecated and has no effect since API level 26.
58     * @param librarySearchPath the list of directories containing native
59     * libraries, delimited by {@code File.pathSeparator}; may be
60     * {@code null}
61     * @param parent the parent class loader
62     */
63    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
64            String librarySearchPath, ClassLoader parent) {
65        this(dexPath, optimizedDirectory, librarySearchPath, parent, false);
66    }
67
68    /**
69     * @hide
70     */
71    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
72            String librarySearchPath, ClassLoader parent, boolean isTrusted) {
73        super(parent);
            //存放dex的路徑
74        this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
75
76        if (reporter != null) {
77            reportClassLoaderChain();
78        }
79    }
80
81  
113    /**
114     * Constructs an instance.
115     *
116     * dexFile must be an in-memory representation of a full dexFile.
117     *
118     * @param dexFiles the array of in-memory dex files containing classes.
119     * @param parent the parent class loader
120     *
121     * @hide
122     */
123    public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
124        // TODO We should support giving this a library search path maybe.
125        super(parent);
126        this.pathList = new DexPathList(this, dexFiles);
127    }
128
129    @Override
130    protected Class<?> findClass(String name) throws ClassNotFoundException {
131        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
132        Class c = pathList.findClass(name, suppressedExceptions);
133        if (c == null) {
134            ClassNotFoundException cnfe = new ClassNotFoundException(
135                    "Didn't find class \"" + name + "\" on path: " + pathList);
136            for (Throwable t : suppressedExceptions) {
137                cnfe.addSuppressed(t);
138            }
139            throw cnfe;
140        }
141        return c;
142    }
281}

2. PathClassLoader.java

public class PathClassLoader extends BaseDexClassLoader {
26    /**
27     * Creates a {@code PathClassLoader} that operates on a given list of files
28     * and directories. This method is equivalent to calling
29     * {@link #PathClassLoader(String, String, ClassLoader)} with a
30     * {@code null} value for the second argument (see description there).
31     *
32     * @param dexPath the list of jar/apk files containing classes and
33     * resources, delimited by {@code File.pathSeparator}, which
34     * defaults to {@code ":"} on Android
35     * @param parent the parent class loader
36     */
37    public PathClassLoader(String dexPath, ClassLoader parent) {
38        super(dexPath, null, null, parent);
39    }
40
41    /**
42     * Creates a {@code PathClassLoader} that operates on two given
43     * lists of files and directories. The entries of the first list
44     * should be one of the following:
45     *
46     * <ul>
47     * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
48     * well as arbitrary resources.
49     * <li>Raw ".dex" files (not inside a zip file).
50     * </ul>
51     *
52     * The entries of the second list should be directories containing
53     * native library files.
54     *
55     * @param dexPath the list of jar/apk files containing classes and
56     * resources, delimited by {@code File.pathSeparator}, which
57     * defaults to {@code ":"} on Android
58     * @param librarySearchPath the list of directories containing native
59     * libraries, delimited by {@code File.pathSeparator}; may be
60     * {@code null}
61     * @param parent the parent class loader
62     */
63    public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
64        super(dexPath, null, librarySearchPath, parent);
65    }
66}
  1. DexClassLoader.java

public class DexClassLoader extends BaseDexClassLoader {
36    /**
37     * Creates a {@code DexClassLoader} that finds interpreted and native
38     * code.  Interpreted classes are found in a set of DEX files contained
39     * in Jar or APK files.
40     *
41     * <p>The path lists are separated using the character specified by the
42     * {@code path.separator} system property, which defaults to {@code :}.
43     *
44     * @param dexPath the list of jar/apk files containing classes and
45     *     resources, delimited by {@code File.pathSeparator}, which
46     *     defaults to {@code ":"} on Android
47     * @param optimizedDirectory this parameter is deprecated and has no effect since API level 26.
48     * @param librarySearchPath the list of directories containing native
49     *     libraries, delimited by {@code File.pathSeparator}; may be
50     *     {@code null}
51     * @param parent the parent class loader
52     */
53    public DexClassLoader(String dexPath, String optimizedDirectory,
54            String librarySearchPath, ClassLoader parent) {
55        super(dexPath, null, librarySearchPath, parent);
56    }
57}
  1. ClassLoader.java

 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // First, check if the class has already been loaded
            //從JVM緩存中已經加載的Class中進行查找,已經加載過,則直接返回   
     //findLoadedClass返回會先判斷當前的類加載器是否是BootClassLoader?如果不是,那么就將當前的加載器傳遞給VMClassLoader : 如果是,則給VMClassLoader傳遞空值進去
//     最后再通過native方法在緩存中查找
     
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                //父類加載器加載
                try {
                    if (parent != null) {
                        //雙親委托,遞歸交給父類加載器進行加載,
                        c = parent.loadClass(name, false);
                    } else {
                        //此方法返回null
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                //自己進行加載
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    //findClass 系統(tǒng)提供的是會直接拋出異常   throw new ClassNotFoundException(name)
                    //我們可以在自己的類加載器中重寫findClass方法,來做到我們自己去查找加載類的功能
                    c = findClass(name);
                }
            }
            return c;
    }

以上就是筆者想要和大家分享的關于類加載器的一些內容,那么我們實際工作中該如何使用呢?持續(xù)完善中。。。。。。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容