Jvm中class文件如何加載、初始化-創(chuàng)新互聯(lián)

這篇文章主要介紹了Jvm中class文件如何加載、初始化,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比鄲城網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式鄲城網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋鄲城地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。

編寫的java文件在要真正運行時,會首先被編譯成 “.class"結(jié)尾的二進制文件,然后被虛擬機加載。那么在虛擬機中一個class文件要成為java實例,需要經(jīng)歷好幾個步驟:
一、class文件要成為java實例的步驟
1、裝載:裝載階段由三個基本動作完成,要裝載一個類型,java虛擬機必須:
(1)通過該類型的完全限定名,產(chǎn)生一個代表該類型的二進制數(shù)據(jù)流
(2)解析這個二進制數(shù)據(jù)流為方法區(qū)內(nèi)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)
(3)創(chuàng)建一個表示該類型的java.lang.Class的實例
*當(dāng)時用new關(guān)鍵字創(chuàng)建一個對象時,該類的數(shù)據(jù)結(jié)構(gòu)存放在方法區(qū)中,new出的對象存放在堆中
二進制的數(shù)據(jù)流可由以下方式產(chǎn)生:
 1、從本地加載一個java class 文件
 2、通過網(wǎng)絡(luò)上下載一個class文件
3、從一個zip、jar、或者其他文檔中提取class文件    等…
2、驗證:類被裝載后,就要準(zhǔn)備連接,連接的第一步是驗證——確認類型符合java語言規(guī)范,并且不會危及虛擬機的完整性。
類型的檢查——確保除了Object之外的每個類都必須有一個超類,并確保該類的所有超類都已經(jīng)被裝載了
類之間的二進制兼容檢查——檢查final類不能用于子類、檢查final類的方法不能被覆蓋、確保子類和超類之間沒有不兼容的方法
——檢查所有的常量池入口相互之間一致
——檢查常量池中的所有特殊字符串是否符合格式
——檢查字節(jié)碼的完整性(最為復(fù)雜的一步)
3、準(zhǔn)備:在準(zhǔn)備階段java虛擬機為類變量分配內(nèi)存,設(shè)置默認初始值,但在到達初始化之前,類變量都沒有被初始化為真正的初始值。即:我們在類中聲明  int  a = 3;但在這一步,a的致被賦予類型的默認值 0  int a =0;java虛擬機不支持boolean 類型,在內(nèi)部,boolean變量會被默認的設(shè)置為int類型的0,即初始化成false.
4、解析:經(jīng)過驗證和準(zhǔn)備之后,就進入了解析過程。解析就是在類型的常量池中尋找類、接口、字段、以及方法的符號引用,把這些引用替換成為直接引用的過程
5、初始化:初始化就是賦予一個變量真正的初始值
如我們定義 private static int a=1; 此時就是給a賦值1
二、動態(tài)鏈接和解析
  class文件把所有的符號引用保存在——常量池中,每一個 class文件都有一個常量池。每一個被虛擬機裝載類或者接口 都有一個內(nèi)部版本的常量池,被稱為運行時常量池。
常量池的解析——當(dāng)程序運行時,某個特定的符號引用要被使用, 首先要被解析。解析過程就是根據(jù) 符號引用查找到實體, 在把符號引用替換成為 直接引用的過程。每個符號引用都只被解析一次
早解析——預(yù)先解析所有的符號引用,從初始類開始,到后續(xù)的各個類,知道所有的符號引用都被解析。
遲解析——在訪問每一個符號引用的最后一刻才去解析。(也可選擇兩種情況之間的折衷策略)
——程序執(zhí)行都是在第一次 實際訪問一個符號引用時才會拋出錯誤,對于用戶來說,看上去都是 遲解析
——java虛擬機會把所有具有相同字符串順序的字符串文字處理成一個String對象。即:如果有多個類使用同一個字符串“Hello”,java虛擬機只會創(chuàng)建一個具有“Hello ”值的String對象 來表示所有的字符串文字。
——任何的byte、short、char返傭www.fx61.com,的值在被壓入棧中時, 都會先被轉(zhuǎn)換成int型
——涉及byte、short、char的運算操作會首先把他們都轉(zhuǎn)換成int類型,進行計算然后得到int結(jié)果,如果需要byte等結(jié)果,需要進行顯示轉(zhuǎn)換。
——java虛擬機中內(nèi)存只能以對象形式在堆中進行分配,如果需要可考慮基本類型包裝器
——java所使用的同步機制是監(jiān)視器,java中的監(jiān)視器支持兩種線程:互斥和協(xié)作。java虛擬機是通過鎖來實現(xiàn)互斥,是通過Object的wait和notify方法來實現(xiàn)協(xié)作
——只有當(dāng)絕對確定等待區(qū)中只有一個線程掛起的時候才應(yīng)使用notify,只要存在同時有多個線程掛起的可能性,就應(yīng)該使用notify all。否則可能導(dǎo)致某個特定的線程在等待區(qū)中等待時間過長,甚至永遠就不會蘇醒。
——堆和方法區(qū)是被所有線程共享的 
——會被多線程訪問的兩種數(shù)據(jù):保存在堆中的實例變量,保存在方法區(qū)中的類變量
——不需要進行保護的變量:java棧中的局部變量,該數(shù)據(jù)是擁有該線程的線程私有的
——當(dāng)虛擬機裝載一個class文件的時候,會創(chuàng)建一個java.lang.Class類的實例。當(dāng)鎖住一個類的時候,其實就是鎖住那個類的Class對象。
三、jvm內(nèi)置的三大類加載器
BootStrap類加載器(BootStrapClassLoader):根類加載器。該加載器沒有父加載器,負責(zé)加載虛擬機的核心類庫,如:java.lang.*等,java.lang.Object就是由根加載器加載的
Extension 類加載器(ExtClassLoader):它的父加載器為根加載器,也就是上面那個。它從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫,或者從jdk的安裝目錄jre/lib/ext子目錄中加載類庫。該類是純java類是lava.lang.ClassLoader類的子類
System系統(tǒng)類加載器(AppClassLoader),也稱為應(yīng)用類加載器,其父加載器為擴展類加載器,上面那個。它從環(huán)境變量classpath中多指定的目錄中加載。它是用戶自定義類加載器的默認父加載器,該類是純java類是lava.lang.ClassLoader類的子類
注意:使用Class.forName("com.test.Test1")進行類裝載時,會自動執(zhí)行類中的靜態(tài)代碼塊,但不會執(zhí)行構(gòu)造方法
使用loadClass("com.test.Test1")進行裝載時,不會自動執(zhí)行其中的靜態(tài)代碼塊,也不會執(zhí)行構(gòu)造方法
***:同一個類,由兩個不同的類加載器去加載,會被認為是兩個不相同的類,在方法區(qū)中會有兩份該類的類信息
只有使用啟動類加載器加載的類,比如:java.lang.Strong、java.lang.Object 等類,在方法區(qū)中只有一份類信息。
 判斷兩個類是否相等的基礎(chǔ)是,這兩個類的類加載器是不是同一個
初始化:對于類的初始化階段,虛擬機規(guī)范規(guī)定了5種情況下必須立即對類進行初始化
1、遇到new、getstatic、putstatic、invokestatic這四條字節(jié)碼指令時,如果類之前沒有進行過初始化會進行初始化。這四條字節(jié)碼對應(yīng)的是:new 實例、靜態(tài)字段取值、靜態(tài)字段賦值、靜態(tài)字段調(diào)用。
2、使用java.lang.refleat包的方法進行反射調(diào)用
3、當(dāng)初始化一個類時,如果發(fā)現(xiàn)其父類還沒有被初始化,需要先初始化其父類
4、當(dāng)虛擬機啟動,需要執(zhí)行main方法的類
5、當(dāng)使用LDK1.7的動態(tài)預(yù)言支持時,如果一個java.lang.invole.MethodHandle實例的最后解析結(jié)果是REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄。
以下幾種情況需要注意:
1、對于靜態(tài)字段,只有直接定義這個字段的類或者接口才會被初始化,如果是通過子類引用父類中的靜態(tài)字段,只會觸發(fā)父類的初始化。
2、常量在編譯階段會存入調(diào)用類的常量池中,本質(zhì)上并沒有直接引用到定義類的常量,因此不會觸發(fā)定義常量的類的初始化。備注:只有編譯器能確定之的常量才會進行該操作,編譯器無法確定的常量值,還是會觸發(fā)目標(biāo)類的初始化。
例如:public static final String uuid = UUID.randomUUID().toString();  這行代碼,當(dāng)其他類在引用uuid時,會觸發(fā)定義該uuid的類的初始化
3、通過數(shù)組定義來引用類,不會觸發(fā)類的初始化 例如: Super[ ] s = new Super[10]; 這行代碼并不會觸發(fā)Super類的初始化
4、當(dāng)一個接口初始化的時候,并不要求其父接口也被初始化,只有真正使用到父接口的時候才會初始化。
四、case class與class的區(qū)別
1、初始化的時候,不需要new,當(dāng)然你也可以加上,普通類一定需要加上new
class ABC(name:String){
def ff(): Unit ={
}
}
case class ABC1(name:String){
def ff1(): Unit ={
}
}
val abc1=ABC1("fg")
val abc= new ABC("xx")
2、toString的實現(xiàn)更加漂亮
println(abc1.toString)
println(abc.toString)
3、默認實現(xiàn)了equals   hashcode
4、默認是可以序列化的,也就是實現(xiàn)了Serializable
5、自動從scala.Producet中繼承了一些函數(shù)
6、case class構(gòu)造函數(shù)的參數(shù)是publiec級別的,我們可以直接訪問
7、支持模式匹配

感謝你能夠認真閱讀完這篇文章,希望小編分享的“Jvm中class文件如何加載、初始化”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián)建站,關(guān)注創(chuàng)新互聯(lián)網(wǎng)站制作公司行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。

網(wǎng)頁標(biāo)題:Jvm中class文件如何加載、初始化-創(chuàng)新互聯(lián)
網(wǎng)頁路徑:http://muchs.cn/article10/psigo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)、微信小程序、App開發(fā)移動網(wǎng)站建設(shè)、用戶體驗、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)