4、雙親委派機制


介紹

Java虛擬機對class文件采用的是按需加載的方式,也就是說當需要使用該類時才會將它的class文件加載到內存生成class對象。而且加載某個類的class文件時,Java虛擬機采用的是雙親委派模式,即把請求交由父類處理,他是一種任務委派模式。

工作原理

在看工作原理前,我們先來看看一個案例

public class StringTest {
    public static void main(String[] args) {
        String string = new String();
        System.out.println("你好,Java");
    }
}

運行結果:
你好,Java

我們都知道,String是java.lang包下面的類,那如果我自己創建一個java.lang包,然后在這個包下面建一個String對象,那么他會去加載哪個String呢?我們下面來看一下
新建java.lang包,寫一個String類:

package java.lang;
public class String {
    static {
        System.out.println("自定義String類的靜態代碼塊");
    }
}

我們繼續運行,發現還是輸出的你好,Java

根據輸出結果,我們可以知道,它並沒有去加載我們自定義的String類,而是加載的Java自帶的那個String類,這是為什么呢?我們接下來討論。

雙親委派機制工作原理:

image
1、如果一個類加載器收到了類加載請求,它並不會自己先去加載,而是把這個請求委托給父類的加載器去執行,
2、如果父類加載器還存在其父類加載器,則進一步向上委托,依次遞歸,請求最終將到達頂層的啟動類加載器。
3、如果父類加載器可以完成類加載任務,就成功返回,倘若父類加載器無法完成此加載任務,子加載器才會嘗試自己去加載,這就是雙親委派模式

雙親委派機制舉例

image
程序中,我們需要用到SPI接口,SPI接口屬於核心API,就使用雙親委派機制,一直到引導類加載器,引導類加載器去加載rt.jar包,就把SPI的核心jar加載過來了。rt中會存在一些接口,接口需要具體的實現類了,這就涉及到一些第三方的jar包了(這里我們加載的JDBC.jar)。這里由於是第三方jar包,這就不屬於引導類加載器了,而是需要我們的系統類加載器了(這里就有了反向委派,一直委派到系統類加載器),系統類加載器是由當前線程的ContextClasssLoader獲取到的,由它來加載jdbc的具體實現類jdbc里面的API

雙親委派機制優勢

1、避免類的重復加載
2、保護程序安全,防止核心API被隨意篡改
​ ->自定義類:java.lang.String
​ ->自定義類:java.lang.ShkStart

沙箱安全機制

自定義String類,但是在加載自定義String類的時候會率先使用引導類加載器加載,而引導類加載器在加載的過程中會先加載jdk自帶的文件(rt.jar包中java\lang\String.class),報錯信息說沒有main方法,就是因為加載的是rt.jar包中的String類。這樣可以保證對java核心源代碼的保護,這就是沙箱安全機制。

其他

在JVM中表示兩個class對象是否為同一個類存在的兩個必要條件:
	1、類的完整類名必須一致,包括包名
	2、加載這個類的ClassLoader(指ClassLoader實例對象)必須相同

換句話說,在JVM中,即使這兩個類對象(Class對象)來源同一個Class文件,被同一個虛擬機所加載,但只要加載他們的ClassLoader實例對象不同,那么這兩個類對象也是不相等的。

對類加載器的引用

JVM必須知道一個類型是由啟動類加載器加載的還是由用戶類加載器加載的,如果一個類型是由用戶類加載器加載的,那么JVM會將這個類加載器的一個引用作為類型信息的一部分保存在方法區中。當解析一個類型到另一個類型的引用的時候,JVM需要保證這兩個類型的類加載器是相同的。
Java程序對類的使用方式分為:主動使用和被動使用

  • 主動使用,又分為7中情況:
    • 創建類的實例
    • 訪問某個類或接口的靜態變量,或者對該靜態變量賦值
    • 調用類的靜態方法
    • 反射(比如:Class.forName("com.shiro.test"))
    • 初始化一個類的子類
    • Java虛擬機啟動時被標明為啟動類的列
    • JDK 7 開始提供的動態語言支持:
      • Java.lang.invoke.MethodHandle實例的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic句柄對應的類沒有初始化,則初始化
  • 除了以上七種情況,其他使用Java類的方式都被看作是對類的被動使用,都不會導致類的初始化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM