本文目錄一覽:
- 1、java 類載入機制有什麼用
- 2、JVM之class載入過程
- 3、描述一下JVM載入class文件的原理?
- 4、java虛擬機位元組碼執行和類載入機制有什麼關係
- 5、深入java虛擬機,絕版和深入理解Java虛擬機:JVM高級特性與最佳實踐。
java 類載入機制有什麼用
AVA類載入機制詳解
「代碼編譯的結果從本地機器碼轉變為位元組碼,是存儲格式發展的一小步,卻是變成語言發展的一大步」,這句話出自《深入理解JAVA虛擬機》一書,後面關於jvm的系列文章主要都是參考這本書。
JAVA源碼編譯由三個過程組成:
1、源碼編譯機制。
2、類載入機制
3、類執行機制
我們這裡主要介紹編譯和類載入這兩種機制。
一、源碼編譯
代碼編譯由JAVA源碼編譯器來完成。主要是將源碼編譯成位元組碼文件(class文件)。位元組碼文件格式主要分為兩部分:常量池和方法位元組碼。
二、類載入
類的生命周期是從被載入到虛擬機內存中開始,到卸載出內存結束。過程共有七個階段,其中到初始化之前的都是屬於類載入的部分
載入—-驗證—-準備—-解析—–初始化—-使用—–卸載
系統可能在第一次使用某個類時載入該類,也可能採用預載入機制來載入某個類,當運行某個java程序時,會啟動一個java虛擬機進程,兩次運行的java程序處於兩個不同的JVM進程中,兩個jvm之間並不會共享數據。
1、載入階段
這個流程中的載入是類載入機制中的一個階段,這兩個概念不要混淆,這個階段需要完成的事情有:
1)通過一個類的全限定名來獲取定義此類的二進位位元組流。
2)將這個位元組流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
3)在java堆中生成一個代表這個類的Class對象,作為訪問方法區中這些數據的入口。
由於第一點沒有指明從哪裡獲取以及怎樣獲取類的二進位位元組流,所以這一塊區域留給我開發者很大的發揮空間。這個我在後面的類載入器中在進行介紹。
2、準備階段
這個階段正式為類變數(被static修飾的變數)分配內存並設置類變數初始值,這個內存分配是發生在方法區中。
1、注意這裡並沒有對實例變數進行內存分配,實例變數將會在對象實例化時隨著對象一起分配在JAVA堆中。
2、這裡設置的初始值,通常是指數據類型的零值。
private static int a = 3;
這個類變數a在準備階段後的值是0,將3賦值給變數a是發生在初始化階段。
3、初始化階段
初始化是類載入機制的最後一步,這個時候才正真開始執行類中定義的JAVA程序代碼。在前面準備階段,類變數已經賦過一次系統要求的初始值,在初始化階段最重要的事情就是對類變數進行初始化,關注的重點是父子類之間各類資源初始化的順序。
java類中對類變數指定初始值有兩種方式:1、聲明類變數時指定初始值;2、使用靜態初始化塊為類變數指定初始值。
初始化的時機
1)創建類實例的時候,分別有:1、使用new關鍵字創建實例;2、通過反射創建實例;3、通過反序列化方式創建實例。
new Test();
Class.forName(「com.mengdd.Test」);
2)調用某個類的類方法(靜態方法)
Test.doSomething();
3)訪問某個類或介面的類變數,或為該類變數賦值。
int b=Test.a;
Test.a=b;
4)初始化某個類的子類。當初始化子類的時候,該子類的所有父類都會被初始化。
5)直接使用java.exe命令來運行某個主類。
除了上面幾種方式會自動初始化一個類,其他訪問類的方式都稱不會觸發類的初始化,稱為被動引用。
1、子類引用父類的靜態變數,不會導致子類初始化。
public class SupClass
{ public static int a = 123;
static
{
System.out.println(“supclass init”);
}
}public class SubClass extends SupClass
{ static
{
System.out.println(“subclass init”);
}
}public class Test
{ public static void main(String[] args)
{
System.out.println(SubClass.a);
}
}
執行結果:
supclass init123
2、通過數組定義引用類,不會觸發此類的初始化
public class SupClass
{ public static int a = 123;
static
{
System.out.println(“supclass init”);
}
}public class Test
{ public static void main(String[] args)
{
SupClass[] spc = new SupClass[10];
}
}
執行結果:
3、引用常量時,不會觸發該類的初始化
public class ConstClass
{ public static final String A= “MIGU”;
static
{
System.out.println(“ConstCLass init”);
}
}public class TestMain
{ public static void main(String[] args)
{
System.out.println(ConstClass.A);
}
}
執行結果:
MIGU
用final修飾某個類變數時,它的值在編譯時就已經確定好放入常量池了,所以在訪問該類變數時,等於直接從常量池中獲取,並沒有初始化該類。
初始化的步驟
1、如果該類還沒有載入和連接,則程序先載入該類並連接。
2、如果該類的直接父類沒有載入,則先初始化其直接父類。
3、如果類中有初始化語句,則系統依次執行這些初始化語句。
在第二個步驟中,如果直接父類又有直接父類,則系統會再次重複這三個步驟來初始化這個父類,依次類推,JVM最先初始化的總是java.lang.Object類。當程序主動使用任何一個類時,系統會保證該類以及所有的父類都會被初始化。
JVM之class載入過程
java虛擬機把描述類的數據從class文件載入到內存,並對數據進行 校驗/準備/解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這個過程被稱作虛擬機的類載入機制。
稱作虛擬機的類載入機制。
loading – linking (verification – preparation – resolution)- resolution)-initializing
loading: 把class文件load到內存中,採用雙親委派,主要是為了安全性
verification: 校驗class文件是否符合標準
preparation: 靜態變數分配內存並設初始值的階段(不包括實例變數)
resolution:把符號引用轉換為直接引用
initializing:靜態變數賦初始值
類載入的過程主要分為三個部分:載入、連接、初始化這三個階段。
類的載入指的是將類的.class文件中的二進位數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個這個類的java.lang.Class對象,用來封裝類在方法區類的對象。主要步驟可以分為下面的三件事情:
載入階段完成後,虛擬機外部的 二進位位元組流就按照虛擬機所需的格式存儲在方法區之中,而且在Java堆中也創建一個java.lang.Class類的對象,這樣便可以通過該對象訪問方法區中的這些數據。
類的載入的最終產品是位於堆區中的Class對象。Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的介面。載入類的方式有以下幾種:
2.載入器
JVM的類載入是通過ClassLoader及其子類來完成的,類的層次關係和載入順序可以由下圖來描述:
1.BootstrapClassLoader(啟動類載入器)
在連接裡面又可以被分成3個小階段,分別是:驗證,準備,解析
1.驗證(目的):
2.驗證內容:
驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的位元組流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。驗證階段大致會完成4個階段的檢驗動作:
驗證階段是非常重要的,但不是必須的,它對程序運行期沒有影響,如果所引用的類經過反覆驗證,那麼可以考慮採用-Xverifynone參數來關閉大部分的類驗證措施,以縮短虛擬機類載入的時間。
3.準備:
在準備階段,為靜態變數的初值為jvm默認的初值,而不是我們在程序中設定的初值。jvm默認為靜態變數的初值是這樣的
4.解析:
這一階段的任務就是把常量池中的符號引用轉換為直接引用 什麼是符號引用,什麼是直接引用。
1.工作內容:
JVM負責主要對類變數(類變數就是static修改的變數)進行初始化這裡主要對類變數(類變數就是static修改的變數)進行初始化,初始化主要有兩個方式:
2.初始化時機:
類初始化時機:只有當對類的主動使用的時候才會導致類的初始化,類的主動使用包括以下六種:
3.初始化順序:
如果有父類,則順序是:父類static方法/static變數賦值 – 子類static方法/static變數賦值
三、結語:
上面介紹的就是類(class)的載入,包含它的載入、鏈接、初始化。
Android進階知識點,我最近整理了許多,裡面講解的非常詳細。取
技術進階手冊丶面試題綱丶核心筆記資料。
描述一下JVM載入class文件的原理?
Java語言是一種具有動態性的解釋型語言,類(class)只有被載入到JVM中後才能運行。當運行指定程序時,JVM會將編譯生成的.class文件按照需求和一定的規則載入到內存中,並組織成為一個完整的Java應用程序。這個載入過程是由類載入器來完成的,具體來說,就是由ClassLoader和它的子類來實現的。類載入器本身也是一個類,其實質是把類文件從硬碟讀取到內存中。
類的載入方式分為隱式載入與顯式載入兩種。隱式載入指的是程序在使用new等方法創建對象時,會隱式地調用類的載入器把對應的類載入到JVM中。顯式載入指的是通過直接調用class.forName()方法來把所需要的類載入到JVM中。
任何一個工程項目都是由許多個類組成的,當程序啟動時,只把需要載入的類載入到JVM中,其他類只有被使用到的時候才會被載入,採用這種方法,一方面可以加快載入速度,另外一方面可以節約程序運行過程中對內存的開銷。此外,在Java語言中,每個類或介面都對應一個.class文件,這些文件可以被看成一個個可以被動態載入的單元,因此當只有部分類被修改時,只需要重新編譯變化的類即可,而不需要重新編譯所有文件,因此加快了編譯速度。
java虛擬機位元組碼執行和類載入機制有什麼關係
沒什麼關係
編譯成.class是為了在不同平台的虛擬機上都能運行
類的載入機制則是語言特性方面的東西
這倆不是一個體系的概念,不應該放在一起討論
深入java虛擬機,絕版和深入理解Java虛擬機:JVM高級特性與最佳實踐。
市面上關於jvm的書少之又少,要不是周志明出的這本深入理解java虛擬機,那麼中文jvm的書籍可以說是有10年的空隙了,上一版還是02年的《java虛擬機規範》了。\x0d\x0a從時效上來說,《深入java虛擬機》出自2000年,技術上已然是滯後很多了。\x0d\x0a所以這兩者比較,絕對推薦後者。\x0d\x0a\x0d\x0a另外單《深入理解java虛擬機》一書來評價,絕對算是一本好書了,掌握此書內容後,基本可以解決java程序員日常遇到的虛擬機先關問題(OOM,調優,GC等),以及應付各種關於該條目的面試筆試問題。\x0d\x0a其中,java內存管理,類載入機制,垃圾回收建議重點閱讀\x0d\x0a\x0d\x0a國外的了解不多,但是就目前來看,建議樓主先吃透周志明老師的這本。有基礎還想深入的話,java虛擬機規範這種官方標準文檔放著呢。
原創文章,作者:TMXT,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/149883.html