1. 程式人生 > >Java類載入機制

Java類載入機制

類載入機制

概念

類載入器把class檔案中的二進位制資料讀入到記憶體中,存放在方法區,然後在堆區建立一個java.lang.Class物件,用來封裝類在方法區內的資料結構。

1、載入: 查詢並載入類的二進位制資料(把class檔案裡面的資訊載入到記憶體裡面)

2、連線: 把記憶體中類的二進位制資料合併到虛擬機器的執行時環境中(1)驗證:確保被載入的類的正確性。包括 A、類檔案的結構檢查:檢查是否滿足Java類檔案的固定格式 B、語義檢查:確保類本身符合Java的語法規範 C、位元組碼驗證:確保位元組碼流可以被Java虛擬機器安全的執行。位元組碼流是操作碼組成的序列。每一個操作碼後面都會跟著一個或者多個運算元。位元組碼檢查這個步驟會檢查每一個操作碼是否合法。 D、 二進位制相容性驗證:確保相互引用的類之間是協調一致的。(2)準備:為類的靜態變數分配記憶體,並將其初始化為預設值(3)解析:把類中的符號引用轉化為直接引用(比如說方法的符號引用,是有方法名和相關描述符組成,在解析階段,JVM把符號引用替換成一個指標,這個指標就是直接引用,它指向該類的該方法在方法區中的記憶體位置)

3、初始化:為類的靜態變數賦予正確的初始值。當靜態變數的等號右邊的值是一個常量表達式時,不會呼叫static程式碼塊進行初始化。只有等號右邊的值是一個執行時運算出來的值,才會呼叫static初始化。

雙親委派模型

1、當一個類載入器收到類載入請求的時候,它首先不會自己去載入這個類的資訊,而是把該請求轉發給父類載入器,依次向上。所以所有的類載入請求都會被傳遞到父類載入器中,只有當父類載入器中沒有找到所需的類,子類載入器才會自己嘗試去載入該類。當前類載入器和所有父類載入器都無法載入該類時,丟擲ClassNotFindException異常。2、意義:提高系統的安全性。使用者自定義的類載入器不可能載入應該由父載入器載入的可靠類。(比如使用者定義了一個惡意程式碼,自定義的類載入器首先讓系統載入器去載入,系統載入器檢查該程式碼不符合規範,於是就不繼續載入了)3、定義類載入器:如果某個類載入器能夠載入一個類,那麼這個類載入器就叫做定義類載入器4、初始類載入器:定義類載入器及其所有子載入器都稱作初始類載入器。5、執行時包:(1)由同一個類載入器載入並且擁有相同包名的類組成執行時包(2)只有屬於同一個執行時包的類,才能訪問包可見(default)的類和類成員。作用是 限制使用者自定義的類冒充核心類庫的類去訪問核心類庫的包可見成員。6、載入兩份相同的class物件的情況:A和B不屬於父子類載入器關係,並且各自都載入了同一個類。

特點:

1、全盤負責:當一個類載入器載入一個類時,該類所依賴的其他類也會被這個類載入器載入到記憶體中。2、快取機制:所有的Class物件都會被快取,當程式需要使用某個Class時,類載入器先從快取中查詢,找不到,才從class檔案中讀取資料,轉化成Class物件,存入快取中。

兩種型別的類載入器

1、 JVM自帶的類載入器(3種):(1) 根類載入器(Bootstrap):

a、C++編寫的,程式設計師無法在程式中獲取該類
b、負責載入虛擬機器的核心庫,比如java.lang.Object
c、沒有繼承ClassLoader類

(2) 擴充套件類載入器(Extension):

a、Java編寫的,從指定目錄中載入類庫
b、父載入器是根類載入器
c、是ClassLoader的子類
d、如果使用者把建立的jar檔案放到指定目錄中,也會被擴充套件載入器載入。

(3) 系統載入器(System)或者應用載入器(App):

a、Java編寫的
b、父載入器是擴充套件類載入器
c、從環境變數或者class.path中載入類
d、是使用者自定義類載入的預設父載入器
e、是ClassLoader的子類

2、 使用者自定義的類載入器:(1)Java.lang.ClassLoader類的子類(2)使用者可以定製類的載入方式(3)父類載入器是系統載入器(4)編寫步驟:

A、繼承ClassLoader
B、重寫findClass方法。從特定位置載入class檔案,得到位元組陣列,然後利用defineClass把位元組陣列轉化為Class物件

(5)為什麼要自定義類載入器? A、 可以從指定位置載入class檔案,比如說從資料庫、雲端載入class檔案B、 加密:Java程式碼可以被輕易的反編譯,因此,如果需要對程式碼進行加密,那麼加密以後的程式碼,就不能使用Java自帶的ClassLoader來載入這個類了,需要自定義ClassLoader,對這個類進行解密,然後載入。

PS

問題:Java程式對類的執行有幾種方式:1、 主動使用(6種情況):// JVM必須在每個類“首次 主動使用”的時候,才會初始化這些類。

(1) 建立類的例項(2) 讀寫某個類或者介面的靜態變數(3) 呼叫類的靜態方法(4) 同過反射的API(Class.forName())獲取類(5) 初始化一個類的子類(6) JVM啟動的時候,被標明啟動類的類(包含Main方法的類)// 只有當程式使用的靜態變數或者靜態方法確實在該類中定義時,該可以認為是對該類或者介面的主動使用。2、 被動使用:除了主動使用的6種情況,其他情況都是被動使用,都不會導致類的初始化。3、 JVM規範允許類載入器在預料某個類將要被使用的時候,就預先載入它。如果該class檔案缺失或者存在錯誤,則在程式“首次 主動使用”的時候,才報告這個錯誤。(Linkage Error錯誤)。如果這個類一直沒有被程式“主動使用”,就不會報錯。

類載入機制與介面:1、 當Java虛擬機器初始化一個類時,不會初始化該類實現的介面。2、 在初始化一個介面時,不會初始化這個介面父介面。3、 只有當程式首次使用該介面的靜態變數時,才導致該介面的初始化。

ClassLoader:1、 呼叫Classloader的loadClass方法去載入一個類,不是主動使用,因此不會進行類的初始化。

類的解除安裝:1、 有JVM自帶的三種類載入器(根、擴充套件、系統)載入的類始終不會解除安裝。因為JVM始終引用這些類載入器,這些類載入器使用引用他們所載入的類,因此這些Class類物件始終是可到達的。2、 由使用者自定義類載入器載入的類,是可以被解除安裝的。