1. 程式人生 > >Java 類載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC

Java 類載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC

類載入是Java程式執行的第一步,研究類的載入有助於瞭解JVM執行過程,並指導開發者採取更有效的措施配合程式執行。 研究類載入機制的第二個目的是讓程式能動態的控制類載入,比如熱部署等,提高程式的靈活性和適應性。 一、簡單過程 Java程式執行的場所是記憶體,當在命令列下執行: java HelloWorld 命令的時候,JVM會將HelloWorld.class載入到記憶體中,並形成一個Class的物件HelloWorld.class。 其中的過程就是類載入過程: 1、尋找jre目錄,尋找jvm.dll,並初始化JVM; 2、產生一個Bootstrap Loader(啟動類載入器); 3、Bootstrap Loader自動載入Extended Loader(標準擴充套件類載入器),並將其父Loader設為Bootstrap Loader。 4、Bootstrap Loader自動載入AppClass Loader(系統類載入器),並將其父Loader設為Extended Loader。 5、最後由AppClass Loader載入HelloWorld類。 以上就是類載入的最一般的過程。 二、類載入器各自搜尋的目錄

為了弄清楚這個問題,首先還要看看System類的API doc文件。

1、Bootstrap Loader(啟動類載入器):載入System.getProperty("sun.boot.class.path")所指定的路徑或jar。 2、Extended Loader(標準擴充套件類載入器ExtClassLoader):載入System.getProperty("java.ext.dirs")所指定的路徑或jar。在使用Java執行程式時,也可以指定其搜尋路徑,例如:java -Djava.ext.dirs=d:/projects/testproj/classes HelloWorld 3、AppClass Loader(系統類載入器AppClassLoader):載入System.getProperty("java.class.path")所指定的路徑或jar。在使用Java執行程式時,也可以加上-cp來覆蓋原有的Classpath設定,例如: java -cp ./lavasoft/classes HelloWorld ExtClassLoader和AppClassLoader在JVM啟動後,會在JVM中儲存一份,並且在程式執行中無法改變其搜尋路徑。如果想在執行時從其他搜尋路徑載入類,就要產生新的類載入器。 三、類載入器的特點
1、執行一個程式時,總是由AppClass Loader(系統類載入器)開始載入指定的類。 2、在載入類時,每個類載入器會將載入任務上交給其父,如果其父找不到,再由自己去載入。 
3、Bootstrap Loader(啟動類載入器)是最頂級的類載入器了,其父載入器為null. 四、類載入器的獲取 很容易,看下面例子 public  class HelloWorld {  
         public  static  void main(String[] args) {  
                 HelloWorld hello =  new HelloWorld();  
                 Class c = hello.getClass();  
                 ClassLoader loader = c.getClassLoader();  
                 System.out.println(loader);  
                 System.out.println(loader.getParent());  
                 System.out.println(loader.getParent().getParent());  
         }  
} 列印結果:
[email protected]
  
[email protected]  
null  

Process finished with exit code 0 從上面的結果可以看出,並沒有獲取到ExtClassLoader的父Loader,原因是Bootstrap Loader(啟動類載入器)是用C語言實現的,找不到一個確定的返回父Loader的方式,於是就返回null。 五、類的載入 類載入有三種方式: 1、命令列啟動應用時候由JVM初始化載入 2、通過Class.forName()方法動態載入 3、通過ClassLoader.loadClass()方法動態載入 三種方式區別比較大,看個例子就明白了: public  class HelloWorld {  
         public  static  void main(String[] args)  throws ClassNotFoundException {  
                 ClassLoader loader = HelloWorld. class.getClassLoader();  
                 System.out.println(loader);  
                 //使用ClassLoader.loadClass()來載入類,不會執行初始化塊  
                 loader.loadClass( "Test2");  
                 //使用Class.forName()來載入類,預設會執行初始化塊  
//                 Class.forName("Test2");  
                 //使用Class.forName()來載入類,並指定ClassLoader,初始化時不執行靜態塊  
//                 Class.forName("Test2", false, loader);  
         }  
} public  class Test2 {  
         static {  
                 System.out.println( "靜態初始化塊執行了!");  
         }  
} 分別切換載入方式,會有不同的輸出結果。 六、自定義ClassLoader 為了說明問題,先看例子: package test;  

import java.net.MalformedURLException;  
import java.net.URL;  
import java.net.URLClassLoader;  

/** 
* 自定義ClassLoader 

* @author leizhimin 2009-7-29 22:05:48 
*/
  
public  class MyClassLoader {  
         public  static  void main(String[] args)  throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException {  
                 URL url =  new URL( "file:/E://projects//testScanner//out//production//testScanner");  
                 ClassLoader myloader =  new URLClassLoader( new URL[]{url});  
                 Class c = myloader.loadClass( "test.Test3");  
                 System.out.println( "----------");  
                 Test3 t3 = (Test3) c.newInstance();  
         }  
} public  class Test3 {  
         static {  
                 System.out.println( "Test3的靜態初始化塊執行了!");  
         }  
} 執行後: ----------  
Test3的靜態初始化塊執行了!  

Process finished with exit code 0 可以看出自定義了ClassLoader myloader = new URLClassLoader(new URL[]{url});已經成功將類Test3載入到記憶體了,並通過預設構造方法構造了物件Test3 t3 = (Test3) c.newInstance(); 有關ClassLoader還有很重要一點: 同一個ClassLoader載入的類檔案,只有一個Class例項。但是,如果同一個類檔案被不同的ClassLoader載入,則會有兩份不同的ClassLoader例項(前提是著兩個類載入器不能用相同的父類載入器)。

在java.lang包裡有個ClassLoader類,ClassLoader 的基本目標是對類的請求提供服務,按需動態裝載類和資
源,只有當一個類要使用(使用new 關鍵字來例項化一個類)的時候,類載入器才會載入這個類並初始化。
一個Java應用程式可以使用不同型別的類載入器。例如Web Application Server中,Servlet的載入使用開發
商自定義的類載入器, java.lang.String在使用JVM系統載入器,Bootstrap Class Loader,開發商定義的其他類
則由AppClassLoader載入。在JVM裡由類名和類載入器區別不同的Java型別。因此,JVM允許我們使用不同
的載入器載入相同namespace的java類,而實際上這些相同namespace的java類可以是完全不同的類。這種
機制可以保證JDK自帶的java.lang.String是唯一的。
2. 載入類的兩種方式:
(1)  隱式方式
使用new關鍵字讓類載入器按需求載入所需的類
(2)  顯式方式
由 java.lang.Class的forName()方法載入
public static Class forName(String className)
public static Class forName(String className, boolean initialize,ClassLoader loader)
引數說明:
        className - 所需類的完全限定名
        initialize - 是否必須初始化類(靜態程式碼塊的初始化)
        loader - 用於載入類的類載入器

呼叫只有一個引數的forName()方法等效於 Class.forName(className, true, loader)。
這兩個方法,最後都要連線到原生方法forName0(),其定義如下:
private static native Class forName0(String name, boolean initialize,ClassLoader loader)
 throws ClassNotFoundException;
只有一個引數的forName()方法,最後呼叫的是:
forName0(className, true, ClassLoader.getCallerClassLoader());
而三個引數的forName(),最後呼叫的是:
forName0(name, initialize, loader);
所以,不管使用的是new 來例項化某個類、或是使用只有一個引數的Class.forName()方法,內部都隱含
了“載入類 + 執行靜態程式碼塊”的步驟。而使用具有三個引數的Class.forName()方法時,如果第二個引數
為false,那麼類載入器只會載入類,而不會初始化靜態程式碼塊,只有當例項化這個類的時候,靜態程式碼塊
才會被初始化,靜態程式碼塊是在類第一次例項化的時候才初始化的。
直接使用類載入器
獲得物件所屬的類 : getClass()方法
獲得該類的類載入器 : getClassLoader()方法
3.執行java XXX.class的過程
找到JRE——》找到jvm.dll——》啟動JVM並進行初始化——》產生Bootstrap Loader——》
載入ExtClassLoader——》載入AppClassLoader——》執行java XXX.class


ClassLoader是用來處理類載入的類,它管理著具體類的執行時上下文。

1.ClassLoader存在的模組意義:

1)從java的package定義出發:

   classloader是通過分層的關聯方式來管理執行中使用的類,不同的classloader中管理的類是不相同的,或者即便兩個類毫無二致(除了路徑)也是不同的兩個類,在進行強制轉換時也會丟擲ClassCastException。所以,通過classloader的限制,我們可以建立不同的package路徑以區別不同的類(注意這裡的“不同”是指,命名和實現完全一致,但是有不同的包路徑。)。那麼也是因為有特定的classloader,我們可以實現具體模組的載入,而不影響jvm中其他類,即發生類載入的衝突。

2)但是,如果兩個在不同路徑下的類(我們假定,這兩個類定義中,不存在package宣告,完全一樣的兩個類),經過不同的classloader載入,這兩個類在jvm中產生的例項可以相互轉換嗎?

答案是否定的。即便這兩個類除了存在位置不同之外,都完全一樣。經由不同classloader載入的兩個類依然是不同的兩個物件。通過Class.newInstance()或者Class.getConstructor().newInstance()產生的物件是完全不同的例項。

以上兩種情況,package可以使得我們的軟體架構清晰,但那不是最終作用,如果跟classloader結合起來理解,效果更好。

2.ClassLoader的類載入機制:

   ClassLoader作為java的一個預設抽象類,給我們帶來了極大的方便,如果我們要自己實現相應的類載入演算法的話。

   每個類都有一個對應的class與之繫結,並且可以通過MyClass.class方式來獲取這個Class物件。通過Class物件,我們就能獲取載入這個類的classloader。但是,我們現在要研究的是,一個類,是如何通過classloader載入到jvm中的。

   其中有幾個關鍵方法,值得我們瞭解一番:

   protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException;

我們可以假設一個例項在建立時,例如通過new方式,是經由如此步驟實現:ClassLoader.loadClass("classname",false).newInstance()。

接下來需要考慮的是loadClass方法為我們做了哪些工作?如何跟對應的.class檔案結合,如何將對應的檔案變成我們的Class物件,如何獲得我們需要的類?

在ClassLoader類中,已經有了loadClass預設實現。我們結合原始碼說明一下:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

相關推薦

Java 載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC

類載入是Java程式執行的第一步,研究類的載入有助於瞭解JVM執行過程,並指導開發者採取更有效的措施配合程式執行。 研究類載入機制的第二個目的是讓程式能動態的控制類載入,比如熱部署等,提高程式的靈活性和適應性。 一、簡單過程 Java

【正文】Java載入器( CLassLoader ) 死磕 4: 神祕的雙親委託機制

【正文】Java類載入器(  CLassLoader ) 死磕4:  神祕的雙親委託機制 本小節目錄 4.1. 每個類載入器都有一個parent父載入器 4.2. 類載入器之間的層次關係 4.3. 類的載入次序 4.4 雙親委託機制原理與沙箱機制 4.5. forName方法和load

jvm之java載入機制載入器(ClassLoader)的詳解

     當程式主動使用某個類時,如果該類還未被載入到記憶體中,則JVM會通過載入、連線、初始化3個步驟來對該類進行初始化。如果沒有意外,JVM將會連續完成3個步驟,所以有時也把這個3個步驟統稱為類載入或類初始化。                             

java載入器——ClassLoader

web rac rgb 好的 全盤負責機制 安全 trac 字節 如何 Java的設計初衷是主要面向嵌入式領域,對於自己定義的一些類,考慮使用依需求載入原則。即在程序使用到時才載入類,節省內存消耗,這時就可以通過類載入器來動態載入。 假設你平時僅僅是做web開發,那應該

Java載入ClassLoader的解析

index html dir obj ble body 6.4 odin 普通 //參考 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 類載入器基本概念 類載

從阿里巴巴面試題到java載入機制

首先很經典的阿里巴巴面試題 加上我自己的一些疑惑程式碼 public class Text { public static int k = 0; public final int k1 = 3; //自己加的 public static Text t1 = new Text("

Java載入器( CLassLoader ) 死磕9: 上下文載入器原理和案例

【正文】Java類載入器(  CLassLoader ) 死磕9:  上下文載入器原理和案例 本小節目錄 9.1. 父載入器不能訪問子載入器的類 9.2. 一個寵物工廠介面 9.3. 一個寵物工廠管理類 9.4 APPClassLoader不能訪問子載入器中的類 9.5. 執行緒上下文

Java載入器( CLassLoader ) 死磕 6: 自定義網路載入

【正文】Java類載入器(  CLassLoader ) 死磕 6:  自定義網路類載入器 本小節目錄 6.1. 自定義網路類載入器的類設計 6.2. 檔案傳輸Server端的原始碼 6.3. 檔案傳輸Client端的原始碼 6. 4 自定義載入器SocketClassLoader的原始

Java載入器( CLassLoader ) 死磕8: 使用ASM,和載入器實現AOP

【正文】Java類載入器(  CLassLoader ) 死磕8:  使用ASM,和類載入器實現AOP 本小節目錄 8.1. ASM位元組碼操作框架簡介 8.2. ASM和訪問者模式 8.3. 用於增強位元組碼的事務類 8.4 通過ASM訪問註解 8.5. 通過ASM注入AOP事務程式

Java載入器( CLassLoader ) 死磕7: 基於加密的自定義網路載入器 本小節目錄

【正文】Java類載入器(  CLassLoader ) 死磕7:  基於加密的自定義網路載入器 本小節目錄 7.1. 加密傳輸Server端的原始碼 7.2. 加密傳輸Client端的原始碼 7.3. 使用亦或實現簡單加密和解密演算法 7. 網路加密SafeClassLoader的原

Java載入器( CLassLoader ) 死磕5: 自定義一個檔案系統的classLoader

【正文】Java類載入器(  CLassLoader ) 死磕5:  自定義一個檔案系統classLoader 本小節目錄 5.1. 自定義類載入器的基本流程 5.2. 入門案例:自定義檔案系統類載入器 5.3. 案例的環境配置 5.4 FileClassLoader 案例實現步驟 5

Java載入器( CLassLoader ) 死磕 3: 揭祕 ClassLoader抽象基

  【正文】Java類載入器(  CLassLoader ) 死磕 3: 揭祕 ClassLoader抽象基類 (1)一個載入器的parent是誰? (2)為什麼優先從parent載入,而不是從自己的地盤載入?欲知後事如何,請看下回分解。 原始碼: 程式碼工程:  class

Java載入器( CLassLoader ) 死磕 1、2: 匯入 & 分類

JAVA類載入器 死磕系列 目錄 by   瘋狂創客圈 1.匯入1.1. 從class檔案的載入開始1.2. 什麼是類載入器2. JAVA類載入器分類2.1. 作業系統的環境變數2.2. Bootstrap ClassLoader(啟動類載入器)2.3. Extention ClassL

java載入機制和自定義載入

類載入順序 上圖所示的是類載入的順序,按照大的順序可以分為載入、連結、初始化 其中連結又可以分成驗證、準備、解析三個步驟 載入 1.將類的class檔案讀入到記憶體中 載入類檔案的方式有: 1. 本機檔案載入 2.jar包載入 3.網路載入 4.原始檔動態編譯載入

淺談Java載入機制

最近在學習 Tomcat 架構,其中很重要的一個模組是類載入器,因為以前學習的不夠深入,所以趁這個機會好好把類載入機制搞明白。 概述 類載入器主要分為兩類,一類是 JDK 預設提供的,一類是使用者自定義的。 JDK 預設提供三種類載入器 Bootstrap ClassLo

深入理解Java載入機制(一)

1 前言: 在上一篇文章一文讓你明白 Java 位元組碼中, 我們瞭解了java位元組碼的解析過程,那麼在接下來的內容中,我們來了解一下類的載入機制。 2 題外話 Java的核心是什麼?當然是JVM了,所以說了解並熟悉JVM對於我們理解Java語言非常重要,不管你是做Java還是Andr

Java 載入機制詳解

一、類載入器   類載入器(ClassLoader),顧名思義,即載入類的東西。在我們使用一個類之前,JVM需要先將該類的位元組碼檔案(.class檔案)從磁碟、網路或其他來源載入到記憶體中,並對位元組碼進行解析生成對應的Class物件,這就是類載入器的功能。我們可以利用類載入器,實現類的動態載入。 二、類的

Java載入機制

類載入機制 概念 類載入器把class檔案中的二進位制資料讀入到記憶體中,存放在方法區,然後在堆區建立一個java.lang.Class物件,用來封裝類在方法區內的資料結構。 1、載入: 查詢並載入類的二進位制資料(把class檔案裡面的資訊載入到記憶體裡面) 2

JVM——Java載入機制

class Singleton{ private static Singleton singleton = new Singleton(); public static int value1; public static int valu

JAVA 載入機制學習筆記

JAVA 類生命週期     如上圖所示,Java類的生命週期如圖所示,分別為載入、驗證、準備、解析、初始化、使用、解除安裝。其中驗證、準備、解析這三個步驟統稱為連結。   載入:JVM根據全限定名來獲取一段二進位制位元組流,將二進位制流轉化為方法區的執行時資料結構,在記憶體中生成一個代表