類的加載
何爲類加載器,簡單的說就是JVM通過類加載器ClassLoader,把.class文件中的信息,拼裝成Class對象放入內存中。JVM的類加載器,就是字節碼和JVM的橋樑。如下圖所示,我們寫好的.java文件經過編譯器,編譯成.class的二進制文件(字節碼),然後通過類加載器把.class文件讀到內存中,組成我們使用的Class對象。
A 在方法區,生成該類運行時的數據結構,如類信息(版本、字段,方法,接口等描述信息),常量,靜態變量等;
B 在Java堆中,生成該類的java.lang.Class對象,一方面封裝方法區中對應的信息,另一方面構建可被使用的Class類結構。具體可以參考JDK的API和源碼。
Class 類的實例表示正在運行的Java應用程序中的類和接口。Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass()自動構造的。
當需要創建Class的實例時,再到堆中查找該類的Class對象,整合方法區中的信息構建該類的實例對象。
加載模型
從J2SE1.2開始,JVM使用了三種類加載器:bootstrap類加載器、extension類加載器和system類加載器。他們是父子繼承的關係,其中bootstrap類加載器在頂端,而system加載器在結構的最底層。 【Bootstrap > Extension > System】Bootstrap Class Loader,是JVM的一部分,加載JVM需要的類。一旦調用java.exe程序,bootstrap類加載器就開始工作。因此,它必須使用native實現。另外,它還負責加載所有的Java核心類,例如java.lang,java.io等。 【系統類】
Extension Class Loader,負責加載標準擴展目錄下面的類。這樣就可以使得編寫程序變得簡單,只需把JAR文件拷貝到擴展目錄下面即可,類加載器會自動的在下面查找。不同的供應商提供的擴展類庫是不同的,Sun公司的JVM的標準擴展目錄是/jdk/jre/lib/ext。 【擴展類】
System Class Loader,是默認的加載器,它在環境變量CLASSPATH目錄下面查找相應的類。 【應用類】
Java的ClassLoader採用全盤負責的委派機制:
全盤負責:當前classLoader要加載一個Class的時候,這個Class所依賴的所有類都需要由這個classLoader來加載。
委派模型:JDK的默認類加載器是System類加載器,每次加載時都會先調用System類加載器。但是他不會馬上load,而是check該類是否存在,如果不存在就會交給父類來處理,一直傳遞到Bootstrap;然後Bootstrap嘗試加載此類,如果查找不到就會傳給Extension,一直往下,直到成功加載此類,否者拋java.lang.ClassNotFoundException異常。
這樣一來一回構成了java加載器的委派模型,每次都是由上到下地加載類。這樣能保證每次都是先加載核心類,一層一層往外加載,再加上類重複加載的檢查,能避免同名類引起的衝突。
試想,你在擴展jar或者是classpath中重寫了一個惡意的java.lang.Object,想加載到JVM中製造破壞。但是,在這種加載模式中,程序需要加載一個java.lang.Object,只會從Bootstrap開始查找,加載類庫的java.lang.Object,所以惡意的java.lang.Object永遠都無法進入JVM內存。
自定義類加載器,一個System類加載器肯定無法滿足所有的需求,而且只能加載classpath的文件,所以用戶可以定義自己的類加載器,定義自己的規則以及加載的方式,加載的來源(如文件系統中的.class文件,jar包,網絡等)。
自定義類加載器要繼承ClassLoader抽象類,其loadClass()方法是final的,所以還得遵循全盤負責委派機制,只是其他方面能夠自由一些。這也是儘量地保證核心類的安全性。
另外,Java運行所需的基本類會預先加載,主要包括rt.jar裏面的.class文件。而其他的類庫,以及用戶自定義的類,就會等到使用的時候才加載進JVM內存。
參考《深入理解java虛擬機》,電子版見我的資源http://download.csdn.net/detail/tiwerbao/6497699