JAVA精髓(進階篇)

JVM內存結構

JVM內存空間包含:方法區、java堆、java棧、本地方法棧。

方法區:是各個線程共享的區域,存放類信息、常量、靜態變量。

java堆:也是線程共享的區域,我們的類的實例就放在這個區域,可以想象你的一個系統會產生很多實例,因此java堆的空間也是最大的。如果java堆空間不足了,程序會拋出OutOfMemoryError異常。

java棧:是每個線程私有的區域,它的生命週期與線程相同,一個線程對應一個java棧,每執行一個方法就會往棧中壓入一個元素,這個元素叫“棧幀”,而棧幀中包括了方法中的局部變量、用於存放中間狀態值的操作棧,這裏面有很多細節,我們以後再講。如果java棧空間不足了,程序會拋出StackOverflowError異常,想一想什麼情況下會容易產生這個錯誤,對,遞歸,遞歸如果深度很深,就會執行大量的方法,方法越多java棧的佔用空間越大。其中類的方法也放在棧中。

本地方法棧:角色和java棧類似,只不過它是用來表示執行本地方法的,本地方法棧存放的方法調用本地方法接口,最終調用本地方法庫,實現與操作系統、硬件交互的目的(調用c語言的,JNI)。

PC寄存器:說到這裏我們的類已經加載了,實例對象、方法、靜態變量都去了自己改去的地方,那麼問題來了,程序該怎麼執行,哪個方法先執行,哪個方法後執行,這些指令執行的順序就是PC寄存器在管,它的作用就是控制程序指令的執行順序。

執行引擎當然就是根據PC寄存器調配的指令順序,依次執行程序指令。

類的加載過程

原理:加載,驗證,準備,解析,初始化

1、加載
簡單的說,類加載階段就是由類加載器負責根據一個類的全限定名來讀取此類的二進制字節流到JVM內部,並存儲在運行時內存區的方法區,然後將其轉換爲一個與目標類型對應的java.lang.Class對象實例(Java虛擬機規範並沒有明確要求一定要存儲在堆區中,只是hotspot選擇將Class對戲那個存儲在方法區中),這個Class對象在日後就會作爲方法區中該類的各種數據的訪問入口。
鏈接
鏈接階段要做的是將加載到JVM中的二進制字節流的類數據信息合併到JVM的運行時狀態中,經由驗證、準備和解析三個階段。


2、驗證
驗證類數據信息是否符合JVM規範,是否是一個有效的字節碼文件,驗證內容涵蓋了類數據信息的格式驗證、語義分析、操作驗證等。
格式驗證:驗證是否符合class文件規範
語義驗證:檢查一個被標記爲final的類型是否包含子類;檢查一個類中的final方法視頻被子類進行重寫;確保父類和子類之間沒有不兼容的一些方法聲明(比如方法簽名相同,但方法的返回值不同)
操作驗證:在操作數棧中的數據必須進行正確的操作,對常量池中的各種符號引用執行驗證(通常在解析階段執行,檢查是否通過富豪引用中描述的全限定名定位到指定類型上,以及類成員信息的訪問修飾符是否允許訪問等)

3、準備
爲類中的所有靜態變量分配內存空間,併爲其設置一個初始值(由於還沒有產生對象,實例變量不在此操作範圍內)
被final修飾的靜態變量,會直接賦予原值;類字段的字段屬性表中存在ConstantValue屬性,則在準備階段,其值就是ConstantValue的值


4、解析
將常量池中的符號引用轉爲直接引用(得到類或者字段、方法在內存中的指針或者偏移量,以便直接調用該方法),這個可以在初始化之後再執行。
可以認爲是一些靜態綁定的會被解析,動態綁定則只會在運行是進行解析;靜態綁定包括一些final方法(不可以重寫),static方法(只會屬於當前類),構造器(不會被重寫)


5、初始化
將一個類中所有被static關鍵字標識的代碼統一執行一遍,如果執行的是靜態變量,那麼就會使用用戶指定的值覆蓋之前在準備階段設置的初始值;如果執行的是static代碼塊,那麼在初始化階段,JVM就會執行static代碼塊中定義的所有操作。
所有類變量初始化語句和靜態代碼塊都會在編譯時被前端編譯器放在收集器裏頭,存放到一個特殊的方法中,這個方法就是<clinit>方法,即類/接口初始化方法。該方法的作用就是初始化一箇中的變量,使用用戶指定的值覆蓋之前在準備階段裏設定的初始值。任何invoke之類的字節碼都無法調用<clinit>方法,因爲該方法只能在類加載的過程中由JVM調用。
如果父類還沒有被初始化,那麼優先對父類初始化,但在<clinit>方法內部不會顯示調用父類的<clinit>方法,由JVM負責保證一個類的<clinit>方法執行之前,它的父類<clinit>方法已經被執行。
JVM必須確保一個類在初始化的過程中,如果是多線程需要同時初始化它,僅僅只能允許其中一個線程對其執行初始化操作,其餘線程必須等待,只有在活動線程執行完對類的初始化操作之後,纔會通知正在等待的其他線程。

類的加載順序

類的加載順序:
Class B:
public class B{
//靜態變量    
static int i=1;
//靜態語句塊
static {
    System.out.println("Class B1:static blocks"+i);
}
//非靜態變量
int j=1;
//靜態語句塊
static{
    i++;
    System.out.println("Class B2:static blocks"+i);
}
//構造函數
public B(){
    i++;
    j++;
    System.out.println("constructor B: "+"i="+i+",j="+j);
}
//非靜態語句塊
{
  i++;
  j++;
  System.out.println("Class B:common blocks"+"i="+i+",j="+j);
}
//非靜態方法
public void bDisplay(){
    i++;
    System.out.println("Class B:static void bDisplay():    "+"i="+i+",j="+j);
    return ;
}
//靜態方法
public static void bTest(){
    i++;
    System.out.println("Class B:static void bTest():    "+"i="+i);
    return ;
}
}
--------------------------------------------------------
Class A:
public class A extends B{
//靜態變量    
static int i=1;
//靜態語句塊
static {
    System.out.println("Class A1:static blocks"+i);
}
//非靜態變量
int j=1;
//靜態語句塊
static{
    i++;
    System.out.println("Class A2:static blocks"+i);
}
//構造函數
public A(){
      super();
    i++;
    j++;
    System.out.println("constructor A: "+"i="+i+",j="+j);
}
//非靜態語句塊
{
  i++;
  j++;
  System.out.println("Class A:common blocks"+"i="+i+",j="+j);
}
//非靜態方法
public void aDisplay(){
    i++;
    System.out.println("Class A:static void aDisplay():    "+"i="+i+",j="+j);
    return ;
}
//靜態方法
public static void aTest(){
    i++;
    System.out.println("Class A:static void aTest():    "+"i="+i);
    return ;
}
}
答:Class B1:static blocks1
   Class B1:static blocks2
   Class A1:static blocks1
   Class A1:static blocks2
Class B:common blocksi=3,j=2
constructor B:i=4,j=3
Class A:common blocksi=3,j=2
constructor A:i=4,j=3
calss A:static void aDisplay<>:i=5,j=3


1.若要加載類A,則先加載執行其父類B(Object)的靜態變量以及靜態語句塊(執行先後順序按排列的先後順序)。
2.然後再加載執行類A的靜態變量以及靜態語句塊。(並且1、2步驟只會執行1次)
3.若需實例化類A,則先調用其父類B的構造函數,並且在調用其父類B的構造函數前,依次先調用父類B中的非靜態變量及非靜態語句塊.最後再調用父類B中的構造函數初始化。
4.然後再依次調用類A中的非靜態變量及非靜態語句塊.最後調用A中的構造函數初始化。( 並且3、4步驟可以重複執行)
5.而對於靜態方法和非靜態方法都是被動調用,即系統不會自動調用執行,所以用戶沒有調用時都不執行,主要區別在於靜態方法可以直接用類名直接調用(實例化對象也可以),而非靜態方法只能先實例化對象後才能調用。

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