Java反射——Class和ClassLoader

概述

當你準備招待客人時,如果你知道你的客人是誰,那麼直接去迎合他的喜好就好了。
但如果你還並不清楚具體客人是誰,那你需要注意了,你所做的準備,要適合所有的客人。

類是對對象的抽象,類的屬性、方法、繼承關係,其對象都同樣擁有。同理,在很多場景下,我們需要對不同的類做一定的歸類、合併和統一處理。這樣,我們就需要對不同的類做一定的抽象,才能達到我們的目的。也就是說,在編譯階段,我們並不知道具體的類是誰,而真正的類是動態賦予的,由此,引出反射系列。

API

反射相關的類主要在java.lang 和 java.lang.reflect包下。
其中,java.lang下主要有以下兩個。

1、Class

類是對象的抽象,Class就是所有類的抽象。
也可以說,Class表示類的類類型。

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
                              }
 

私有構造方法,僅JVM能創建Class對象。

   private Class(ClassLoader loader) {
       // Initialize final field for classLoader.  The initialization value of non-null
       // prevents future JIT optimizations from assuming this final field is null.
       classLoader = loader;
   }

重要方法:
a.創建類型的方法
newInstance()
創建類的新的實例-通過類類型可以創建類的實例對象(需要有無參構造方法)

b.查詢類型的方法

forName()
根據給定的string 類名、類加載器(可選)返回相對應的Class對象

public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}


public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Reflective call to get caller class is only needed if a security manager
            // is present.  Avoid the overhead of making this call otherwise.
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        return forName0(name, initialize, loader, caller);
    }

    /** Called after security check for system loader access checks have been made. */
    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;

可以看到,forName()重載方法,最終都調用了native方法forName0()。其中,forName(String className)方法中設置initialize爲true。

注意:
a.指定的類加載器是用於加載類或者接口的。
b.若該方法中,未給出指定的加載器,會通過bootstrap類加載來加載相應的類。
c.當參數中的initialize爲true,並且該類之前未被初始化過,纔會對類進行初始化。

補充:其他獲取Class的方式
類名爲A

  • A.class (class是類的隱含的靜態成員變量)
  • new A().getClass() (Object的方法getClass)

涉及到類加載機制的部分,下一篇詳細說明。

其他查詢方法:
getName()
getClassLoader()
getField()
getMethod()
getConstructors()

2、ClassLoader

public abstract class ClassLoader {
}

默認類加載器

先看幾個簡單的例子:

ps:註釋爲打印結果,其中,由於Bootstrap ClassLoader爲C++語言編寫,在java下無法打印,因此得到的打印結果爲null。

        System.out.println(ClassTest.class.getClassLoader());//AppClassLoader 
        System.out.println(ClassTest.class.getClassLoader().getParent());//ExtClassLoader加載器
        System.out.println(ClassTest.class.getClassLoader().getParent().getParent());//Bootstrap加載器,打印結果爲null

由上可知,類加載器有三種默認類型:Bootstrap ClassLoader、ExtClassLoader、AppClassLoader。那這三個有什麼分別呢?

  • Bootstrap ClassLoader:Java中最頂層的類加載器,負責加載JDK中的核心類庫,如:rt.jar、resources.jar、charsets.jar等。
  • ExtClassLoader:主要負責加載Java的擴展類庫,負責加載JDK中的擴展類庫。其父類加載器爲Bootstrap ClassLoader。
  • AppClassLoader:應用類加載器(系統類加載器),負責加載classpath路徑下的jar包。其父類加載器爲ExtClassLoader。

除了這三個默認類加載器,當然用戶可以自定義類加載器,但自定義類加載器的父類是AppClassLoader。關係如下:
在這裏插入圖片描述
那麼一個類到底是如何加載的呢?這幾個默認類加載器之間是如何工作的呢?

雙親委派

首先,明確下類加載親在jvm內存模型中的位置。
在這裏插入圖片描述
什麼是雙親委派?
若一個類加載器要加載一個類,先看其父類是否能加載,以此類推,直到最頂層的Bootstrap ClassLoader,若頂層類加載器可以加載即進行加載,若無法加載,纔有最初的類加載器進行加載。

通俗的說,兒子接到活之後,一律不自己做,先給了爸爸,爸爸給了爺爺,爺爺如果可以做就做,不能做,再由兒子一層一層檢查是否可以做。

爲什麼要用這種實現方式?

  • 安全
    若用戶自定義了核心或擴展類庫中的同名類,則不會被成功加載,因爲這些系統默認類已由默認類加載器加載。

  • 避免重複加載
    類加載器之間有了層次優先級關係,就避免了類的重複加載。

java.lang.reflect包下的主要類有:
1、Field
該類提供了動態訪問、設置類或接口的字段功能。

public final
class Field extends AccessibleObject implements Member {
}

2、Method
3、Constructor
4、Array

小結

本篇介紹了反射中的常用的相關類,Class和ClassLoader,介紹了Class抽象的思維,以及類加載機制的“雙親委派”機制。下篇我們重點介紹本文中說明的reflect包的代理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章