好程式設計師Java學習路線分享JVM類載入機制
好程式設計師Java 學習路線分享 JVM 類載入機制 JVM 相關概念
- jdk<br>
jdk ( Java Development Kit ) Java 開發包,是 Java 開發人員用於編譯和除錯程式的一套程式的集合。
- jre<br>
jre ( Java Runtime Evironment ) Java 執行時環境,是執行 Java 程式的平臺,所有的 Java 程式必須在這個平臺中才能執行。
- jvm<br>
jvm ( Java Virtual Machine ) Java 虛擬機器,是用程式碼虛擬出來的計算機,模擬執行計算機的各項功能,它有自己的硬體架構,如:處理器、堆疊、暫存器等,還有自己的一套指令系統,在不同的作業系統上都可以安裝 JVM ,從而實現 Java 程式在不同的作業系統上都能執行, JVM 就是為實現 Java 的跨平臺特性。
JVM 載入類的過程
我們執行Java 程式開發出來後,需要先編譯再執行, JVM 就負責載入類的過程。 <br>
類載入的過程分為:
1. 載入
2. 驗證
3. 準備
4. 解析
5. 初始化
類載入的具體過程
下面詳細介紹下這幾個過程:
1. 載入 <br>
在載入類的過程要完成:
1. 根據類的全名限定符,獲取 class 二進位制流,這個流可以從磁碟上的 class 、 jar 檔案獲得,也可以從網路中獲得。
2. 將類的靜態儲存結構轉化為方法區的執行時動態儲存結構
3. 在記憶體的堆中生成對應的 java.lang.Class 物件,作為方法區的入口
2. 驗證 <br>
載入類完成後,就進入了驗證過程,這個過程保證了前面生成的Class 物件中的資訊,不會危害 JVM 的安全。 <br>
需要驗證的方面有:
1. 檔案格式驗證,是要驗證位元組流是否符合 Class 檔案格式的規範,並且能被當前版本的虛擬機器處理。如驗證魔數是否 0xCAFEBABE ;主、次版本號是否正在當前虛擬機器處理範圍之內;常量池的常量中是否有不被支援的常量型別等等,該驗證階段的主要目的是保證輸入的位元組流能正確地解析並儲存於方法區中,經過這個階段的驗證後,位元組流才會進入記憶體的方法區中儲存,所以後面的三個驗證階段都是基於方法區的儲存結構進行的。
2. 後設資料驗證,是對位元組碼描述的資訊進行語義分析,以保證其描述的資訊符合 Java 語言規範的要求。可能包括的驗證如:這個類是否有父類;這個類的父類是否繼承了不允許被繼承的類;如果這個類不是抽象類,是否實現了其父類或介面中要求實現的所有方法。
3. 位元組碼驗證,主要工作是進行資料流和控制流分析,保證被校驗類的方法在執行時不會做出危害虛擬機器安全的行為。如果一個類方法體的位元組碼沒有透過位元組碼驗證,那肯定是有問題的;但如果一個方法體透過了位元組碼驗證,也不能說明其一定就是安全的。
4. 符號引用驗證,發生在虛擬機器將符號引用轉化為直接引用的時候,這個轉化動作將在“解析階段”中發生。驗證符號引用中透過字串描述的許可權定名是否能找到對應的類;在指定類中是否存在符合方法欄位的描述符及簡單名稱所描述的方法和欄位;符號引用中的類、欄位和方法的訪問性 (private 、 protected 、 public 、 default) 是否可被當前類訪問。
3. 準備 <br>
準備階段會在方法區中為類的靜態變數分配記憶體,並賦給預設值。
```
public static int count = 100;
```
如:上面的count 變數在準備階段會賦值為 0 ,在初始化時再賦值為 100;
4. 解析 <br>
解析階段是虛擬機器將常量池內的符號引用替換為直接引用的過程。
- 符號引用( Symbolic Reference ) <br>
符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機器實現的記憶體佈局無關,引用的目標並不一定已經載入到記憶體中。
- 直接引用( Direct Reference ) <br>
直接引用可以是直接指向目標的指標、相對偏移量或是一個能間接定位到目標的控制程式碼。直接引用是與虛擬機器實現的記憶體佈局相關的,如果有了直接引用,那麼引用的目標必定已經在記憶體中存在。
5. 初始化 <br>
類初始化是類載入過程的最後一步,前面的類載入過程,除了在載入階段使用者應用程式可以透過自定義類載入器參與之外,其餘動作完全由虛擬機器主導和控制。到了初始化階段,才真正開始執行類中定義的Java 程式程式碼。 <br>
初始化階段是執行類構造器<clinit>() 方法的過程。 <clinit>() 方法是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊 (static{} 塊 ) 中的語句合併產生的。
那麼何時執行初始化呢?
1. 建立類的例項
2. 訪問類的靜態變數 ( 除常量外, final 修飾的 )
原因: 常量一種特殊的變數,因為編譯器把他們當作值而不是屬性來對待。
3. 訪問類的靜態方法
4. 反射如 (Class.forName("com.test.Person"))
5. 當初始化一個類時,發現其父類還未初始化,則先呼叫父類的初始化
6. 虛擬機器啟動時,定義了 main() 方法的那個類先初始化
程式碼案例
瞭解了類的載入機制,我們來看一道面試題:
```
public class MySingleton {
private static MySingleton singleton = new MySingleton();
public static int count1 = 0;
public static int count2;
private MySingleton(){
count1++;
count2++;
}
public static MySingleton getInstance(){
return singleton;
}
public static void main(String[] args) {
MySingleton singleton = MySingleton.getInstance();
System.out.println("count1-->"+MySingleton.count1);
System.out.println("count2-->"+MySingleton.count2);
}
}
上面的結果,大多數同學可能認為兩個靜態變數都是1 ,結果比較意外:
```
count1-->0
count2-->1
```
這是為什麼呢?下面我們來分析下:
1. 首先我們知道在類的準備階段會為靜態變數賦預設值: <br>
singleton = null;
count1 = 0;
count2 = 0;
2. 當呼叫類的靜態方法 getInstance 後,引發類的初始化,先執行 new MySingleton() 呼叫構造方法,這時: <br>
count1 = 1;
count2 = 1;
3. 繼續初始化,為變數賦值, count1 賦值為 0 , count2 沒有賦值就保留值 1 ,結果就是 :<br>
count1 = 0;
count2 = 1;
總結
JVM 是程式碼模擬的計算機,有自己的硬體和軟體, JVM 能實現 Java 類的載入和執行,具體載入過程有:載入、驗證、準備、解析、初始化 5 個步驟組成。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2657509/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師Java分享JVM類載入機制程式設計師JavaJVM
- 好程式設計師Java學習路線分享Java面試題之載入機制程式設計師Java面試題
- 好程式設計師Java學習路線分享JVM相關概念程式設計師JavaJVM
- 好程式設計師Java學習路線分享SpringCloud程式設計師JavaSpringGCCloud
- 好程式設計師Java學習路線分享Redis快速入門程式設計師JavaRedis
- 好程式設計師Java學習路線分享Java案例-封裝JDBC工具類程式設計師Java封裝JDBC
- 好程式設計師Java學習路線分享mybatis對映程式設計師JavaMyBatis
- 好程式設計師Java學習路線分享Java框架怎麼搭建程式設計師Java框架
- 好程式設計師Java學習路線分享Java-String常用方法程式設計師Java
- 好程式設計師Java學習路線分享原生Ajax的使用程式設計師Java
- 好程式設計師Java學習路線分享finalize()方法詳解程式設計師Java
- 好程式設計師Java學習路線分享MyBatis之Spring整合程式設計師JavaMyBatisSpring
- 好程式設計師Java學習路線分享MyBatis之基本使用程式設計師JavaMyBatis
- 好程式設計師Java學習路線分享maven是什麼程式設計師JavaMaven
- 好程式設計師Java學習路線分享SpringMVC之MVC概述程式設計師JavaSpringMVC
- 好程式設計師Java分享JVM從哪方面入手學習程式設計師JavaJVM
- 好程式設計師Java學習路線分享Java中的位移運算程式設計師Java
- JVM學習(三)——類載入機制JVM
- 好程式設計師Java學習路線分享三大特性之多型程式設計師Java多型
- 好程式設計師Java學習路線分享Dubbo架構介紹程式設計師Java架構
- 好程式設計師Java學習路線分享多執行緒概念程式設計師Java執行緒
- 好程式設計師Java學習路線分享MySQL目錄結構程式設計師JavaMySql
- 好程式設計師Java學習路線之集程式設計師Java
- 好程式設計師Java學習路線JSP物件程式設計師JavaJS物件
- 好程式設計師Java學習路線分享Java弱引用的理解與使用程式設計師Java
- 好程式設計師Java學習路線分享怎麼理解Java物件導向程式設計師Java物件
- 好程式設計師分享Python從入門到精通最佳學習路線程式設計師Python
- 好程式設計師Java學習路線分享SpringMVC之請求和響應程式設計師JavaSpringMVC
- 好程式設計師Java學習路線分享如何處理中文引數程式設計師Java
- 好程式設計師Java學習路線分享MyBatis之關聯查詢程式設計師JavaMyBatis
- 好程式設計師Java學習路線分享Spring常見面試題程式設計師JavaSpring面試題
- JVM學習筆記——類載入機制JVM筆記
- 好程式設計師大資料學習路線分享Scala系列之抽象類程式設計師大資料抽象
- 好程式設計師大資料學習路線分享MAPREDUCE程式設計師大資料
- 好程式設計師大資料學習路線分享SparkSQl程式設計師大資料SparkSQL
- 好程式設計師大資料學習路線分享Hadoop機架感知程式設計師大資料Hadoop
- 好程式設計師Java培訓分享Java類載入的過程概述程式設計師Java
- 好程式設計師Java學習路線分享5分鐘瞭解計數排序程式設計師Java排序