6.類加載器的分類 -- 引導類加載器、擴展類加載器、應用程序類加載器、用戶自定義類加載器

1.類加載器分類

JVM支持兩種類型的類加載器,分別爲引導類加載器(Bootstrap ClassLoader)和自定義類加載器(User-Defined ClassLoader)。
這裏的自定義加載器指的不是開發人員自己定義的類加載器,而是指的所有繼承自ClassLoader的類加載器。包括擴展類加載器、應用程序類加載器、用戶自定義類加載器(程序員自己寫的)三種。
在這裏插入圖片描述
常見的類加載器如下圖所示:
第一個藍色框表示的是引導類加載器;剩下的所有的類加載器都是自定義的類加載器。BootStrapClassLoader使用C語言實現,自定義類加載器使用Java語言實現。
注意:圖中不是表示的繼承關係。擴展類加載器和系統類加載器(應用程序類加載器AppClassLoader)都是繼承自ClassLoader,所以將他們劃分爲自定義加載器。
在這裏插入圖片描述
下面的Java例子,可以幫助理解類加載器之間的關係:

public class ClassLoaderTest {
    public static void main(String[] args) {

        //獲取系統類加載器,輸出AppClassLoader,說明系統類加載器就是應用程序類加載器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //獲取系統類加載器的上層:輸出ExtClassLoader,說明系統類加載器的上層是擴展類加載器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@1540e19d

        //獲取擴展類加載器的上層:輸出null,獲取不到引導類加載器。雖然獲取不到,但是擴展類加載器的上層是引導類加載器
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);//null

        //輸出AppClassLoader。說明對於用戶自定義類來說:默認使用系統類加載器進行加載
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //打印的也是null,和獲取擴展類的上層的輸出是一樣。可以證明String類使用引導類加載器進行加載的。擴展開來:---> Java的核心類庫都是使用引導類加載器進行加載的。
        ClassLoader classLoader1 = String.class.getClassLoader();
        System.out.println(classLoader1);//null


    }
}

1.1 引導類加載器(Bootstrap ClassLoader)

1.引導類加載器使用C/C++語言實現,在JVM內部
2.用於加載Java核心類庫
3.不繼承ClassLoader
4.還用於加載擴展類加載器和應用程序類加載器
5.只加載包名爲java,javax,sun開頭的類
在這裏插入圖片描述

1.2 擴展類加載器(Extension ClassLoader)

1.使用java語言編寫,JVM自帶
2.繼承自ClassLoader
3.父類加載器爲啓動類加載器
4.從java.ext.dirs指定的路徑下加載類庫;或者從JDK安裝目錄的jre/lib/ext目錄下加載類庫。
5.如果用戶自定義的jar包放在jre/lib/ext下,也會自動由擴展類加載器加載
在這裏插入圖片描述

1.3 應用程序類加載器(AppClassLoader或者稱爲系統類加載器)

1.使用jaca語言編寫,JVM自帶
2.繼承自ClassLoader
3.父類加載器爲啓動類加載器
4.負責加載環境變量classpath或系統屬性java.class.path指定的類庫
5.java中自己寫的類都是由應用程序類加載器加載的
6.可以通過ClassLoader.getSystemClassLoader()方法獲取該類加載器
在這裏插入圖片描述

理解BootstrapClassLoader、ExtClassLoader、AppClassLoader的例子:

public class ClassLoaderTest1 {
    public static void main(String[] args) {
        System.out.println("**********啓動類加載器**************");
        //獲取BootstrapClassLoader能夠加載的api的路徑
        URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();//獲取到的是通過引導類加載的類庫的路徑(輸出參考“引導類能夠加載的類庫路徑”)
        for (URL element : urLs) {
            System.out.println(element.toExternalForm());
        }
        //從上面的路徑中隨意選擇一個類,來看看他的類加載器是什麼:引導類加載器
        ClassLoader classLoader = Provider.class.getClassLoader();
        System.out.println(classLoader); //輸出爲null。說明是引導類加載器加載的

        System.out.println("***********擴展類加載器*************");
        String extDirs = System.getProperty("java.ext.dirs");
        for (String path : extDirs.split(";")) {// 輸出參考“擴展類能夠加載的類庫路徑”圖
            System.out.println(path);
        }

        //從上面的路徑中隨意選擇一個類,來看看他的類加載器是什麼:擴展類加載器
        ClassLoader classLoader1 = CurveDB.class.getClassLoader();
        System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1540e19d

    }
}

引導類能夠加載的類庫路徑:如下圖。主要就是jre/lib/ext目錄下面的jar包。
在這裏插入圖片描述
擴展類能夠加載的類庫路徑:如下圖。主要是jre/lib/ext目錄以及java.ext.dirs指定的路徑下的jar包
在這裏插入圖片描述

1.4 用戶自定義類加載器(程序員自己寫的)

除了上面3種JVM提供的類加載器之外,程序員還可以自己定義類加載器。(簡單瞭解)
在這裏插入圖片描述
自定義加載器實現步驟:
在這裏插入圖片描述
自定義一個類加載器簡單的例子:

public class CustomClassLoader extends ClassLoader { //繼承ClassLoader
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException { //重載findClass方法

        try {
            byte[] result = getClassFromCustomPath(name);
            if(result == null){
                throw new FileNotFoundException();
            }else{
                return defineClass(name,result,0,result.length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        throw new ClassNotFoundException(name);
    }

    private byte[] getClassFromCustomPath(String name){
        //從自定義路徑中加載指定類:細節略
        //如果指定路徑的字節碼文件進行了加密,則需要在此方法中進行解密操作。(這裏可以進行解密操作,防止class文件被反編譯)
        return null;
    }

    public static void main(String[] args) {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        try {
            Class<?> clazz = Class.forName("One",true,customClassLoader);
            Object obj = clazz.newInstance();
            System.out.println(obj.getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章