一、類加載器(ClassLoader)負責加載class文件,class文件在文件開頭有特定的文件標識,而且ClassLoader只負責 class 文件的加載,至於class文件是否可以運行則由Execution Engine決定;java
二、類的加載過程安全
加載class文件 ---> 鏈接(驗證、準備、解析class文件)----> 初始化類的對象 ----> 使用類的對象 -----> 卸載。jvm
(1)加載class文件spa
取類的二進制字節流,經過類的全量命名,將靜態存儲結構房到方法區中,Class(類的定義或結構,即類對象)放到堆中; 設計
(2)初始化類對象3d
執行類的構造器<clinit>,爲類的靜態變量賦予正確的初值;code
構造器包含:static變量、static塊;根據代碼中的順序來決定先執行哪一個;對象
先執行構造器(static變量、static塊),再執行構造方法;blog
三、JDK中的類加載器:遞歸
<1> 啓動類加載器(BootStrap ClassLoader): C++編寫的,虛擬機自帶的加載器;加載$JAVA_HOME/jre/lib/rt.jar
<2> 擴展類加載器(Extension ClassLoader):java編寫;加載$JAVA_HOME/jre/lib/ext/*.jar
<3> 應用程序類加載器(App ClassLoader):java編寫;也叫系統類加載器,加載當前應用的 $classpath 下全部類;
<4> 用戶自定義加載器:Java.Lang.ClassLoader 的子類,用戶能夠定製類的加載方式;
三、類加載器說明
第一步:將 MyHello 類打包成 jar包,而後放入$JAVA_HOME/jre/lib/ext/ 目錄下。 MyHello內容以下:
public class MyHello { public static void main(String[] args) { } }
第二步:編寫以下代碼
public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { //啓動類加載器(BootStrap ClassLoader)
Object object = new Object(); System.out.println("Object-classLoader: " + object.getClass().getClassLoader()); //結果: Object-classLoader: null //擴展類加載器 (Extension ClassLoader)
Class myHello = Class.forName("com.yufeng.jvm.hello.MyHello"); System.out.println("MyHello-classLoader: " + myHello.getClassLoader()); //結果:MyHello-classLoader: sun.misc.Launcher$ExtClassLoader@7ea987ac //應用類加載器 (App ClassLoader)
Demo1 classLoaderDemo1 = new Demo1(); System.out.println("Demo1-classLoader: " + classLoaderDemo1.getClass().getClassLoader()); //①結果:Demo1-classLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println("Demo1-classLoader-parent: " + classLoaderDemo1.getClass().getClassLoader().getParent()); //②結果:Demo1-classLoader-parent: sun.misc.Launcher$ExtClassLoader@2503dbd3
System.out.println("Demo1-classLoader-parent-parent: " + classLoaderDemo1.getClass().getClassLoader().getParent().getParent()); //③結果:Demo1-classLoader-parent-parent: null
} }
從以上的①、②、③能夠看出,啓動類加載器是擴展類加載器的父類,擴展類加載器是應用加載器的父類。
打印出的Object的類加載器爲null,表示它是根加載器,即啓動類加載器。
四、類加載器的雙親委派機制
某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次遞歸,若父類加載器能夠完成類加載任務,就成功返回;只有父類加載器沒法完成此加載任務時,才本身去加載。
這樣設計爲了保證java的一種安全特性--------沙箱機制(防止惡意代碼對java的破壞);
例:若本身新建了一個String類(classpath路徑下),則類加載器是應用程序類加載器;加載的時候程序類加載器委託父類加載器加載(即擴展類加載器),擴展類加載器去委託啓動類加載器去加載,rt.jar中有String.class文件,則會加載這個Class,不會加載本身新建的那個String類。