天天看點

JVM(Java SE 11版本)加載類和接口

本文介紹了Java虛拟機(Java SE 11版本)加載類和接口。

加載類和接口

加載是指查找具有特定名稱的類或接口類型的二進制形式的過程。典型的做法是,查找事先由Java編譯器從源代碼計算而來二進制表示,但也可能是通過動态計算。

二進制形式最終會構造成一個Class對象。

加載的精确語義在Java Java Machine Specification,Java SE 11 Edition的第5章中給出。在這裡,我們從Java程式設計語言的角度概述了該過程。

類或接口的二進制格式通常是上面引用的Java虛拟機規範Java SE 11版中描述的類檔案格式,但隻要滿足第13.1節中規定的要求,其他格式也是可能的。

類ClassLoader的方法defineClass可用于從類檔案格式的二進制表示構造Class對象。

表現良好的類加載器維護這些性質:

  • 給定相同的名稱,一個好的類加載器應該總是傳回相同的類對象。
  • 如果類加載器L1将類C的加載委托給另一個加載器L2,那麼對于作為直接超類或C的直接超接口出現的任何類型T,或作為C中的字段類型,或作為類型方法的正式參數或

    C中的構造函數,或者作為C,L1和L2中方法的傳回類型應該傳回相同的Class對象。

惡意類加載器可能違反這些性質。但是,它不能破壞類型系統的安全性,因為Java虛拟機可以防範這種情況。

有關這些問題的進一步讨論,請參閱Java虛拟機規範,Java SE 11版和Java虛拟機中的動态類加載,作者:Sheng Liang和Gilad Bracha,作為ACO SIGPLAN釋出的OOPSLA '98會議錄。通告,第33卷,第10期,1998年10月,第36-44頁。Java程式設計語言設計的基本原則是運作時類型系統不能被用Java程式設計語言編寫的代碼破壞,即使是這樣的實作也是如此。否則敏感的系統類如ClassLoader和SecurityManager。

加載過程

加載過程由類ClassLoader及其子類實作。

ClassLoader的不同子類可以實作不同的加載政策。特别地,類加載器可以緩存類和接口的二進制表示,基于預期的使用來預取它們,或者将一組相關的類加載在一起。

例如,如果找不到新編譯的類,因為舊版本由類加載器緩存,這些活動可能對正在運作的應用程式不完全透明。但是,類加載器的責任是僅在程式中可能出現的情況下反映加載錯誤,而無需預取或組加載。

如果在類加載期間發生錯誤,那麼将在程式中(直接或間接)使用該類型的任何點抛出類LinkichError的以下子類之一的執行個體:

  • ClassCircularityError:無法加載類或接口,因為它将是自己的超類或超接口(第8.1.4節,第9.1.3節,第13.4.4節)。
  • ClassFormatError:聲稱指定所請求的編譯類或接口的二進制資料格式錯誤。
  • NoClassDefFoundError:相關類加載器無法找到所請求的類或接口的定義。

因為加載涉及新資料結構的配置設定,是以它可能會因OutOfMemoryError而失敗。

參考引用