java平臺無關性
平臺無關性是一種語言在計算機上的運行不受平臺約束,一次編譯,到處執行,
java語言的規范,Class檔案,JVM在java的平臺無關性扮演著重要的角色,
java語言規范
java的基本資料型別的值域和行為都是由自己定義的,而C++的基本資料型別的占位寬度是由所在平臺決定的,
對于int型別,在java中,int占4個位元組,是固定的,在C++中,在16位的計算集中,int型別的長度
占2個位元組,32位計算機上占4個位元組,在64位計算機上,int型別的長度可能占8位元組,
class位元組碼檔案
java在不同平臺的虛擬機都使用統一的位元組碼格式,java虛擬機只與由自己組成的Class檔案進行互動,jvm會自行判斷加載的class檔案是否符合虛擬機的規范,
java虛擬機
在不同的硬體和作業系統上,主要的區別就是指令不同,jvm根據對應的硬體和作業系統生成對應的二進制指令,

JVM類加載系統

類加載機制
java虛擬機把描述類的資料從Class檔案加載到記憶體,經過驗證、準備、決議、初始化后,最終形成可以被java虛擬機直接使用的java型別的程序,
類加載時機
加載、驗證、準備、初始化、卸載這五個階段順序是按部就班的“開始”的,開始強調的是這些步驟可能也是交叉進行的,比如說決議階段可能會在初始化后面(決議階段和驗證、準備都包含在鏈接階段),為了支持java語言的運行時系結特性,(多型,編譯看左邊,運行看右邊)
JVM規范對類加載程序的第一階段“加載”沒有強制性約束,對于初始化階段嚴格規定了有且僅有六種情況必須立即進行初始化(主動參考)
1.遇到new、getStatic、putStatic、invokestatic這四個指令時
2.使用java.lang.reflect包下的方法進行反射呼叫時
3.子類初始化的時候,如果父類還沒有初始化,應該先初始化父類
4.JVM啟動的時候,JVM會先初始化main()所在的類
5.默認介面的實作類初始化的時候,該介面應該在實作類之前初始化
6.使用jdk動態語言支持的時候,java.lang.invoke.MethodHandle實體決議結果為REF_getStatic,REF_putStatic,REF_invokeStatic,REF_newInvokeSpecial四種型別的方法句柄,這些句柄對應的類還沒有進行初始化
被動參考不會出發初始化
1.通過子類參考父類的靜態欄位,只會觸發父類進行初始化,不會引起子類初始化
2.定義的陣列參考類,不會觸發此類初始化
3.一個類呼叫另一個類的靜態常量時,不會引起另一個類的初始化,因為在編譯期,將靜態常量已經放入了常量池
類加載程序
1.加載階段
目的:通過一個類的全限定名獲取此類二進制位元組流,存入到方法區中,生成的class物件,作為外部訪問方法區的入口
獲取位元組流的途徑:java原始碼編譯生成的class檔案,ZIP壓縮包中讀取,網路獲取等
2.鏈接階段
①驗證
驗證主要是為了確保class檔案的位元組流中包含的資訊符合虛擬機的規范,保證加載類的正確性,不會危害虛擬機的安全
驗證方式:
檔案格式驗證:驗證位元組流是否符合class檔案格式的規范,例:是否以魔數開頭、主次版本號是否在當前JVM接受的范圍內
元資料驗證:對位元組碼描述的資訊進行語意分析,對元資料資訊中的資料型別校驗,例:是否繼承Object類
位元組碼驗證:資料流及控制流進行語意分析,確定程式的語意適合法的,符合邏輯的,例:不相關類的強制轉換
符號參考驗證:決議階段,將符號參考轉換為直接參考的時候發生
②準備
對類中定義的變數分配空間和設定類變數的初始值,一般為資料型別的0值,如果是靜態常量(final),在準備階段就設定為定義的值,類變數會分配在方法區,實體變數分配在堆中
③決議
將常量池中符號參考轉換為直接參考的程序
決議操作一般在JVM完成初始化之后進行
符號參考:一組用來描述所參考的目標的符號
直接參考:直接指向目標的指標、相對偏移量或一個間接定位到目標的句柄
3.初始化
執行類構造器<clinit>(),此方法是javac編譯器自動收集類中的所有類變數的賦值動作和靜態代碼塊中陳述句合并而來的,
①編譯器收集類中的類變數和靜態代碼塊的順序是按照源檔案中出現的先后順序進行的
②JVM會先保證父類的<clinit>()方法執行,然后在執行子類的
③如果類中沒有類變數或者靜態代碼塊,可以不生成<clinit>()
④JVM必須保證<clinit>()在多執行緒下被同步加鎖
雙親委派模型

對于任意一個類,都必須由加載他的類加載器和這個類本身一起確定他在JVM中的唯一性
例如:比較兩個類是否相等,只有在這兩個類是由同一個類加載器加載的前提下比較才有意義,就算兩個類來源于同一個class檔案,但是他們是由不同的類加載器加載,這兩個類就一定不相同
啟動類加載器
由c/c++實作,是虛擬機自身的一部分,加載java核心類別庫到虛擬機記憶體(java中獲取加載器型別時,如果回傳null,代表該加載器是啟動類加載器)
擴展類加載器
加載JAVA_HOME/jre/lib/ext目錄下或者從java.ext.dirs系統指定目錄中加載類別庫允許用戶將自定義的jar放置在此目錄下,都有擴展類加載器加載
應用程式加載器
負責加載環境變數classpath或系統屬性java.class.path指定路徑下的類別庫,該類加載器為程式中默認的類加載器
自定義加載器
繼承classloader,并重寫findclass()方法指定位元組碼獲取方式,loadClass模板方法會呼叫findClass
雙親委派模型
一個類加載器收到類加載請求,先檢查請求加載的類是否被加載過,如果沒有,他會將這個請求發送給父類,依次向上發送,直到發送給啟動類加載器,如果啟動類加載器可以完成加載任務,則成功回傳,如果無法完成任務,就交給子類加載器,如果有加載器可以完成,子加載器呼叫自己的findClass()進行加載
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/291459.html
標籤:java
上一篇:用Java撰寫簡單的撲克牌游戲
