1. 程式人生 > >JVM-----類載入(類只需要載入一次就可以,不需要反覆載入)

JVM-----類載入(類只需要載入一次就可以,不需要反覆載入)

一、

1、類從載入到虛擬機器記憶體中開始,到卸載出記憶體為止,它的整個生命週期包括:

載入-驗證-準備-解析-初始化-使用-解除安裝,其中驗證-準備-解析稱為連結。

二、

2、類載入階段虛擬機器需要完成以下事情:

(1)將class檔案位元組碼內容載入到虛擬機器記憶體中。

(2)將這些靜態資料結構轉換為方法區執行時資料結構。

(3)在堆中生成一個代表這個類的Class物件,作為方法區類資料的訪問入口。

3、連結階段

將java類的二進位制程式碼合併到JVM執行狀態之中(即將靜態的位元組碼資料轉換為可執行的資料)。

驗證:確保載入的類資訊符合JVM規範,沒有安全方面的問題。

準備:正式為類變數(static變數)分配記憶體並設定類變數初始化的值,這些記憶體都將在方法區中進行分配。

解析:將虛擬機器常量池中的符號引用替換為直接引用的過程。(注:符號引用是通過一組符號描述目標,而直接引用是通過指標直接或間接的定位到目標)

4、初始化階段

(1)初始化階段是執行類構造器<clinit>()方法的過程,類構造器<clinit>()方法是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊(static塊)中的語句合併產生的。

(2)當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化。

(3)虛擬機器會保證一個類的<clinit>()方法在多執行緒環境中被正確加鎖和同步。

(4)當虛擬機器啟動時,使用者需要制定一個要執行的主類,(有main方法的那個類),虛擬機器會先初始化這個類。

(5)當訪問一個java類的靜態域時,只有真正宣告這個域的類才會被初始化。

三、

5、一定會發生類的初始化(載入)事件(類的主動引用)

(1)new一個類的物件。

(2)使用類的靜態成員(除了final常量)和靜態方法。

(3)使用java.lang.reflect包的方法對類進行反射呼叫(例如:Class.forName("com.shxt.A").

   (4)虛擬機器啟動,java Hello,則一定會初始化Hello類,說白了就是先啟動main方法所在類。

(5)當初始化一個類,如果其父類沒有被初始化,則會先初始化它的父類。

注:類的被動引用,不會發生類的初始化(載入)

(1)通過陣列定義類引用,不會發生此類的初始化(例如A [] arr = new A[10]).

(2) 使用類的常量不會觸發此類的初始化(常量在編譯階段就存入常量池中了)

(3)當訪問一個靜態變數時,只有真正宣告這個變數的類才會被初始化。

例如:

public static void main(String [] args){

    System.out.println(B.width);

}

class B extends A{

}

class A {

    public static int width=100;

}

此時,A會被初始化,但B不會被初始化。

四、

6、類載入器

從java虛擬機器的角度來說,只存在兩種不同的類載入器:一種是啟動類載入器,這個類載入器使用c++實現,是虛擬機器自身的一部分;另一種就是所有其他的類載入器,這些類載入器都是由java實現,且全部繼承自java.lang.ClassLoader。

載入器的關係如下:

(1)啟動類載入器

用來載入java的核心庫(載入JAVA_HOME/jre/lib/rt.jar中的類),啟動類載入器無法被java程式直接使用。

(2)擴充套件類載入器

負責載入java的擴充套件庫(載入JAVA_HOME/jre/ext/*.jar中的類),開發者可以直接使用擴充套件類載入器。

(3)應用程式類載入器(載入classpath中的類),開發者可以直接使用這個類載入器,若應用程式中沒有定義過自己的類載入器,java應用的類都是由它來完成載入的。

(4)自定義類載入器

開發人員可以通過繼承java.lang.ClassLoader類的方式實現自己的類載入器,以滿足一些特殊的需求。

7、雙親委託機制(是代理模式的一種,代理模式:交給其他載入器來載入指定的類)

若一個類載入器收到了類載入請求,它首先不會自己去嘗試載入這個類,而是把這個請求委派給父類載入器去完成,依次追溯,直到最高的爺爺輩的,如果父類載入器可以完成委託任務,就成功返回;只有父類載入器無法完成載入任務時,才自己去載入。

雙親委託機制作用:保證java核心庫的型別安全。

這用機制就保證不會出現使用者自己能定義java.lang.Object類的情況。

即類載入器除了用於載入類,也是安全的最基本的屏障。

注:並不是所有的類載入器都採用雙親委託機制。

tomcat伺服器類載入器也使用代理模式,所不同的是它首先嚐試自己去載入這個類,如果找不到在代理給父類載入器,這與一般的類載入器的順序是相反的。

五、

7、比較兩個類是否相同

比較兩個類是否相同,只有這兩個類是由同一個類載入器載入的前提下才有意義,否則即使這兩個類來自同一個class檔案,只要載入它們的載入器不同,它們就是不同的類。