1. 程式人生 > >JAVA 不同類載入器名稱空間的理解

JAVA 不同類載入器名稱空間的理解

            以前一直有這樣一個疑惑:

       都說在JAVA中,由不同類載入器載入的類在虛擬機器中位於不同的名稱空間下,不同名稱空間下的類相互不可見。

這讓我產生了一個迷惑:如果有一個類A使用了java.util.List類,為什麼在執行時會沒有錯誤。因為按照類載入的雙親委派機制,自己寫的類A一般由系統類載入器載入,而java.util.List肯定是由啟動類載入器(也叫Root類載入器)載入的,所以這兩個類應該不在一個名稱空間下。那在執行時為什麼類A還 是能訪問到java.util.List?

           現在搞明白了,原因如下:

           首先我們明白,每一個JAVA類經過載入後,在虛擬機器中都有一個對應的型別。

           再有以下概念:如果類A被系統類載入器載入,那麼該系統類載入器就是此A在虛擬機器中對應型別的初始類載入器

           Java虛擬機器為每個類載入器維護了一個表,其中記錄了將該類載入器作為初始類載入器的所有型別。在載入一個類時,虛擬機器使用這些列表來決定是否一個類已經被特定的類載入器載入過了(如果該型別在當前類載入器的列表中,就說明已經載入過了,就不再載入)。

           再回到剛到A使用java.util.List的例子,當A被載入後,解析到A使用了List,就會請求載入java.util.List。根據類的載入原理及雙親委派機制。會先請類A的類載入器,即系統類載入器載入java.util.List,系統類當然載入不了這個List,所以它會委派給自己的父載入器,即擴充套件類載入器;同理,最終會由根據類載入器載入這個java.util.List,併成功返回。

          根據Java虛擬機器規範規定,在這個過程中涉及的所有類載入器--即從系統類載入器到根類載入器間,參與過載入的,都被標記為該型別的初始類載入器。換句話說,java虛擬機器為在第一個類載入器維護的表中新增一個型別,用來標明此載入器是該型別的初始類載入器。

          這樣就不難理解類A為何可以使用java.util.List。儘管它們不是由一個載入器載入的,因為在系統類載入器的表中,即維護了型別A,也維護了型別List。