摘要:當前類加載器和所有父類加載器都無法加載該類時,拋出異常。加載兩份相同的對象的情況和不屬于父子類加載器關系,并且各自都加載了同一個類。類加載機制與接口當虛擬機初始化一個類時,不會初始化該類實現的接口。
類加載機制 概念
類加載器把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,對這個類進行解密,然后加載。
問題: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、 由用戶自定義類加載器加載的類,是可以被卸載的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77142.html
摘要:如果需要支持類的動態加載或需要對編譯后的字節碼文件進行解密操作等,就需要與類加載器打交道了。雙親委派模型,雙親委派模型,約定類加載器的加載機制。任何之類的字節碼都無法調用方法,因為該方法只能在類加載的過程中由調用。 jvm系列 垃圾回收基礎 JVM的編譯策略 GC的三大基礎算法 GC的三大高級算法 GC策略的評價指標 JVM信息查看 GC通用日志解讀 jvm的card table數據...
摘要:前面提到,對于數組類來說,它并沒有對應的字節流,而是由虛擬機直接生成的。對于其他的類來說,虛擬機則需要借助類加載器來完成查找字節流的過程。驗證階段的目的,在于確保被加載類能夠滿足虛擬機的約束條件。 Java 虛擬機將字節流轉化為 Java 類的過程。這個過程可分為加載、鏈接以及初始化 三大步驟。 加載是指查找字節流,并且據此創建類的過程。加載需要借助類加載器,在 Java 虛擬機中,類...
摘要:當程序使用某個類時,如果該類還沒被初始化,加載到內存中,則系統會通過加載連接初始化三個過程來對該類進行初始化。一旦一個類被加載到中之后,就不會再次載入了。它既可以從本地文件系統獲取二進制文件來加載類,也可以遠程主機獲取二進制文件來加載類。 當程序使用某個類時,如果該類還沒被初始化,加載到內存中,則系統會通過加載、連接、初始化三個過程來對該類進行初始化。該過程就被稱為類的初始化 類加載 ...
摘要:學習能更深入的理解這門語言,能理解語言底層的執行過程,深入到字節碼層次。 目錄 ? 前言 程序的運行 1.JVM類加載機制 ①一般在什么情況下會去加載一個類?也就是說,什么時候.class字節碼文件中加載這個類到JVM內存里來? ②驗證、準備、初始化 ③初始化 2.類加載器和雙親委派機制 ...
摘要:以上文中的類的加載過程為例,它的加載器為系統類加載器。自定義加載器編寫自定義加載器并不困難,只要繼承抽象類并覆蓋方法就行了。源碼來自參考資料類加載機制與類加載器架構深入探討類加載器 序 我是在關于Java的面試題里了解到類加載器的,在這之前從未想過Java里類是如何被加載、解析的,一直以為只要Import就好了。事實上Java類加載器是一塊非常重要的內容,可以用在類層次劃分、OSGi、...
閱讀 3870·2021-09-10 11:22
閱讀 2324·2021-09-03 10:30
閱讀 3659·2019-08-30 15:55
閱讀 1870·2019-08-30 15:44
閱讀 839·2019-08-30 15:44
閱讀 581·2019-08-30 14:04
閱讀 3041·2019-08-29 17:18
閱讀 1262·2019-08-29 15:04