• <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • 第一部分 Java基礎
    第二部分 Java進階

    Java類加載器面試題

     

     

    1、Java的類加載器的種類都有哪些?

     

    ● 根類加載器(Bootstrap)--C++寫的,看不到源碼;

     

    ● 擴展類加載器(Extension)--加載位置:jre\lib\ext中;

     

    ● 系統(應用)類加載器(System\App) --加載位置:classpath中;

     

    ● 自定義加載器(必須繼承ClassLoader)。

     

     

    2、類什么時候被初始化?

     

    ● 創建類的實例,也就是new一個對象

     

    ● 訪問某個類或接口的靜態變量,或者對該靜態變量賦值

     

    ● 調用類的靜態方法

     

    ● 反射(Class.forName("com.lyj.load"))

     

    ● 初始化一個類的子類(會首先初始化子類的父類)

     

    ● JVM啟動時標明的啟動類,即文件名和類名相同的那個類只有這6中情況才會導致類的類的初始化。

     

    ● 類的初始化步驟:

     

    如果這個類還沒有被加載和鏈接,那先進行加載和鏈接;

     

    假如這個類存在直接父類,并且這個類還沒有被初始化(注意:在一個類加載器中,類只能初始化一次),那就初始化直接的父類(不適用于接口);

     

    加入類中存在初始化語句(如static變量和static塊),那就依次執行這些初始化語句。

     

     

    3、Java類加載體系之ClassLoader雙親委托機制

     

    java是一種類型安全的語言,它有四類稱為安全沙箱機制的安全機制來保證語言的安全性,這四類安全沙箱分別是:

     

    1.類加載體系

     

    2.class文件檢驗器

     

    3.內置于Java虛擬機(及語言)的安全特性

     

    4.安全管理器及Java API

     

    ● 主要講解類的加載體系:

     

    java程序中的.java文件編譯完會生成.class文件,而.class文件就是通過被稱為類加載器的ClassLoader加載的,而ClassLoder在加載過程中會使用“雙親委派機制”來加載.class文件,圖:

     

     

    BootStrapClassLoader:啟動類加載器,該ClassLoader是jvm在啟動時創建的,用于加載$JAVA_HOME$/jre/lib下面的類庫(或者通過參數-Xbootclasspath指定)。由于啟動類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啟動類加載器的引用,所以不能直接通過引用進行操作。

     

    ExtClassLoader:擴展類加載器,該ClassLoader是在sun.misc.Launcher里作為一個內部類ExtClassLoader定義的(即sun.misc.Launcher$ExtClassLoader),ExtClassLoader會加載$JAVA_HOME/jre/lib/ext下的類庫(或者通過參數-Djava.ext.dirs指定)。

     

    AppClassLoader:應用程序類加載器,該ClassLoader同樣是在sun.misc.Launcher里作為一個內部類,AppClassLoader定義的(即sun.misc.Launcher$AppClassLoader),AppClassLoader會加載java環境變量CLASSPATH所指定的路徑下的類庫,而CLASSPATH所指定的路徑可以通過System.getProperty("java.class.path")獲取;當然,該變量也可以覆蓋,可以使用參數-cp,例如:java-cp路徑(可以指定要執行的class目錄)。

     

    CustomClassLoader:自定義類加載器,該ClassLoader是指我們自定義的ClassLoader,比如tomcat的StandardClassLoader屬于這一類;當然,大部分情況下使用AppClassLoader就足夠了。

     

    前面談到了ClassLoader的幾類加載器,而ClassLoader使用雙親委派機制來加載class文件的。ClassLoader的雙親委派機制是這樣的(這里先忽略掉自定義類加載器CustomClassLoader):

     

    1.當AppClassLoader加載一個class時,它首先不會自己去嘗試加載這個類,而是把類加載請求委派給父類加載器ExtClassLoader去完成。

     

    2.當ExtClassLoader加載一個class時,它首先也不會自己去嘗試加載這個類,而是把類加載請求委派給BootStrapClassLoader去完成。

     

    3.如果BootStrapClassLoader加載失敗(例如在$JAVA_HOME$/jre/lib里未查找到該class),會使用ExtClassLoader來嘗試加載;

     

    4.若ExtClassLoader也加載失敗,則會使用AppClassLoader來加載,如果AppClassLoader也加載失敗,則會報出異常ClassNotFoundException。

     

    下面貼下ClassLoader的loadClass(String name,boolean resolve)的源碼:

     

    protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
            // 首先找緩存是否有 class
            Class c=findLoadedClass(name);
            if(c==null){
            //沒有判斷有沒有父類
            try{
            if(parent!=null){
            //有的話,用父類遞歸獲取 class
            c=parent.loadClass(name,false);
    	}else{
            //沒有父類。通過這個方法來加載
            c=findBootstrapClassOrNull(name);}
            }catch(ClassNotFoundException e){
            // ClassNotFoundException thrown if class not found
            // from the non-null parent class loader
            }
            if(c==null){
            // 如果還是沒有找到,調用 findClass(name)去找這個類
            c=findClass(name);}
            }
            if(resolve){
            resolveClass(c);}
            return c;
            }

     

    代碼很明朗:

     

    首先找緩存(findLoadedClass),沒有的話就判斷有沒有parent,有的話就用parent來遞歸的loadClass,然而ExtClassLoader并沒有設置parent,則會通過findBootstrapClassOrNull來加載class,而findBootstrapClassOrNull則會通過JNI方法”private native Class findBootstrapClass(String name)”來使用BootStrapClassLoader來加載class。

     

    如果parent未找到class,則會調用findClass來加載class,findClass是一個protected的空方法,可以覆蓋它以便自定義class加載過程。另外,雖然ClassLoader加載類是使用loadClass方法,但是鼓勵用ClassLoader的子類重寫findClass(String),而不是重寫loadClass,這樣就不會覆蓋了類加載默認的雙親委派機制。

     

    雙親委派托機制為什么安全:

     

    舉個例子,ClassLoader加載的class文件來源很多,比如編譯器編譯生成的class、或者網絡下載的字節碼。而一些來源的class文件是不可靠的,比如我可以自定義一個java.lang.Integer類來覆蓋jdk中默認的Integer類,例如下面這樣:

     

    package java.lang;
    public class Integer {
        public Integer(int value) {
            System.exit(0);
        }
    }

     

    初始化這個Integer的構造器是會退出JVM,破壞應用程序的正常進行,如果使用雙親委派機制的話該Integer類永遠不會被調用,以為委托BootStrapClassLoader加載后會加載JDK中的Integer類而不會加載自定義的這個,可以看下下面這測試個用例:

     

    public static void main(String...args){
            Integer i=new Integer(1);
            System.err.println(i);
    }

     

    執行時JVM并未在new Integer(1)時退出,說明未使用自定義的Integer,于是就保證了安全性。

     

     

    4、描述一下 JVM 加載 class?

     

    JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。

     

    1.由于Java的跨平臺性,經過編譯的Java源程序并不是一個可執行程序,而是一個或多個類文件。

     

    2.當Java程序需要使用某個類時,JVM會確保這個類已經被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的.class文件中的數據讀入到內存中,通常是創建一個字節數組讀入.class文件,然后產生與所加載類對應的Class對象。加載完成后,Class對象還不完整,所以此時的類還不可用。

     

    3.當類被加載后就進入連接階段,這一階段包括驗證、準備(為靜態變量分配內存并設置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟。最后JVM對類進行初始化,包括:如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類;如果類中存在初始化語句,就依次執行這些初始化語句。

     

    4.類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。

     

    5.從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載。JVM不會向Java程序提供對Bootstrap的引用。

     

    ● 下面是關于幾個類加載器的說明:

     

    1.Bootstrap:一般用本地代碼實現,負責加載JVM基礎核心類庫(rt.jar);

     

    2.Extension:從java.ext.dirs系統屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap;

     

    3.System:又叫應用類加載器,其父類是Extension。它是應用最廣泛的類加載器。它從環境變量classpath或者系統屬性java.class.path所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。

     

     

    5、獲得一個類對象有哪些方式?

     

    ● 類型.class,例如:String.class;

     

    ● 對象.getClass(),例如:”hello”.getClass();

     

    ● Class.forName(),例如:Class.forName(“java.lang.String”);

     

    全部教程
  • <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • 面对面棋牌游戏