詳解JAVA類加載機制(推薦)
JAVA源碼編譯由三個過程組成:
1、源碼編譯機制。
2、類加載機制
3、類執(zhí)行機制
我們這里主要介紹編譯和類加載這兩種機制。
一、源碼編譯
代碼編譯由JAVA源碼編譯器來完成。主要是將源碼編譯成字節(jié)碼文件(class文件)。字節(jié)碼文件格式主要分為兩部分:常量池和方法字節(jié)碼。
二、類加載
類的生命周期是從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存結(jié)束。過程共有七個階段,其中到初始化之前的都是屬于類加載的部分
加載----驗證----準(zhǔn)備----解析-----初始化----使用-----卸載
系統(tǒng)可能在第一次使用某個類時加載該類,也可能采用預(yù)加載機制來加載某個類,當(dāng)運行某個java程序時,會啟動一個java虛擬機進程,兩次運行的java程序處于兩個不同的JVM進程中,兩個jvm之間并不會共享數(shù)據(jù)。
1、加載階段
這個流程中的加載是類加載機制中的一個階段,這兩個概念不要混淆,這個階段需要完成的事情有:
1)通過一個類的全限定名來獲取定義此類的二進制字節(jié)流。
2)將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
3)在java堆中生成一個代表這個類的Class對象,作為訪問方法區(qū)中這些數(shù)據(jù)的入口。
由于第一點沒有指明從哪里獲取以及怎樣獲取類的二進制字節(jié)流,所以這一塊區(qū)域留給我開發(fā)者很大的發(fā)揮空間。這個我在后面的類加載器中在進行介紹。
2、準(zhǔn)備階段
這個階段正式為類變量(被static修飾的變量)分配內(nèi)存并設(shè)置類變量初始值,這個內(nèi)存分配是發(fā)生在方法區(qū)中。
1、注意這里并沒有對實例變量進行內(nèi)存分配,實例變量將會在對象實例化時隨著對象一起分配在JAVA堆中。
2、這里設(shè)置的初始值,通常是指數(shù)據(jù)類型的零值。
private static int a = 3;
這個類變量a在準(zhǔn)備階段后的值是0,將3賦值給變量a是發(fā)生在初始化階段。
3、初始化階段
初始化是類加載機制的最后一步,這個時候才正真開始執(zhí)行類中定義的JAVA程序代碼。在前面準(zhǔn)備階段,類變量已經(jīng)賦過一次系統(tǒng)要求的初始值,在初始化階段最重要的事情就是對類變量進行初始化,關(guān)注的重點是父子類之間各類資源初始化的順序。
java類中對類變量指定初始值有兩種方式:1、聲明類變量時指定初始值;2、使用靜態(tài)初始化塊為類變量指定初始值。
初始化的時機
1)創(chuàng)建類實例的時候,分別有:1、使用new關(guān)鍵字創(chuàng)建實例;2、通過反射創(chuàng)建實例;3、通過反序列化方式創(chuàng)建實例。
new Test(); Class.forName(“com.mengdd.Test”);
2)調(diào)用某個類的類方法(靜態(tài)方法)
Test.doSomething();
3)訪問某個類或接口的類變量,或為該類變量賦值。
int b=Test.a; Test.a=b;
4)初始化某個類的子類。當(dāng)初始化子類的時候,該子類的所有父類都會被初始化。
5)直接使用java.exe命令來運行某個主類。
除了上面幾種方式會自動初始化一個類,其他訪問類的方式都稱不會觸發(fā)類的初始化,稱為被動引用。
1、子類引用父類的靜態(tài)變量,不會導(dǎo)致子類初始化。
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); } }
執(zhí)行結(jié)果:
supclass init
123
2、通過數(shù)組定義引用類,不會觸發(fā)此類的初始化
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]; } }
執(zhí)行結(jié)果:
3、引用常量時,不會觸發(fā)該類的初始化
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); } }
執(zhí)行結(jié)果:
MIGU
用final修飾某個類變量時,它的值在編譯時就已經(jīng)確定好放入常量池了,所以在訪問該類變量時,等于直接從常量池中獲取,并沒有初始化該類。
初始化的步驟
1、如果該類還沒有加載和連接,則程序先加載該類并連接。
2、如果該類的直接父類沒有加載,則先初始化其直接父類。
3、如果類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句。
在第二個步驟中,如果直接父類又有直接父類,則系統(tǒng)會再次重復(fù)這三個步驟來初始化這個父類,依次類推,JVM最先初始化的總是java.lang.Object類。當(dāng)程序主動使用任何一個類時,系統(tǒng)會保證該類以及所有的父類都會被初始化。
以上所述是小編給大家介紹的JAVA類加載機制(推薦),希望對大家有所幫助!
上一篇:深入jetty的使用詳解
欄 目:Java編程
本文標(biāo)題:詳解JAVA類加載機制(推薦)
本文地址:http://mengdiqiu.com.cn/a1/Javabiancheng/8498.html
您可能感興趣的文章
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10JVM的垃圾回收機制詳解和調(diào)優(yōu)
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
- 01-10Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)器
- 01-10Java中的浮點數(shù)分析


閱讀排行
本欄相關(guān)
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10JVM的垃圾回收機制詳解和調(diào)優(yōu)
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10J2SE 1.5版本的新特性一覽
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
隨機閱讀
- 04-02jquery與jsp,用jquery
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實例總結(jié)
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子