【Java技術-反射】Java反射機制

        包名: java.lang.reflect.*
        Java反射機制是在運行狀態(Runtime)中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法,獲取它的成員變量;這種動態獲取的信息以及動態調用對象的方法的功能稱爲Java語言的反射機制。

        Java反射機制是Java語言被視爲"準動態"語言的關鍵性質。Java反射機制的核心就是允許在運行時通過Java Reflection APIs來取得已知名字的class類的內部信息(包括其modifiers(諸如public, static等等)、superclass(例如Object)、實現interfaces(例如Serializable),也包括fields和 methods的所有信息),動態地生成此類,並調用其方法或修改其域(甚至是本身聲明爲private的域或方法)。

        Java反射機制主要提供了以下功能:在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調用任意一個對象的方法;生成動態代理。


1. Object
    1.1 Class<?getClass()
    Returns the runtime class of this Object.
例: KeyBoard k = new KeyBoard();
     Class<?> clazz = k.getClass(); 或 Class clazz = k.getClass();

2. Class
        Class對象是Java反射的基礎,它包含了與類相關的信息,事實上,Class對象就是用來創建類的所有對象的。Class對象是java.lang.Class<T>這個類生成的對象,其中類型參數T表示由此 Class 對象建模的類的類型。例如,String.class的類型是 Class<String>;如果將被建模的類未知,則使用Class<?>。以下是Java API的描述:

        Class類的實例表示正在運行的 Java應用程序中的類和接口。枚舉是一種類,註釋是一種接口。每個數組屬於被映射爲Class對象的一個類,所有具有相同元素類型和維數的數組都共享該Class對象。基本的Java類型(booleanbyte、 char、shortintlongfloatdouble)和關鍵字void也表示爲Class對象。

        Class沒有公共構造方法。Class對象是在加載類時由Java虛擬機以及通過調用類加載器中的defineClass方法自動構造的。

        每個類都有一個Class對象。換言之,每當編寫並且編譯了一個新類,就會產生一個Class對象(更恰當的說,是被保存在一個同名的.class文件中)。如果我們想生成這個類的對象,運行這個程序的Java虛擬機(JVM)將使用類加載器子系統,類加載器首先檢查這個類的Class對象是否已經加載。如果尚未加載,默認的類加載器就會根據類名查找.class文件,並將其載入,一旦某個類的Class對象被載入內存,它就被用來創建這個類的所有對象。

獲取Class對象有三種方式:

       (1) Object類的getClass()方法,例:

            Class c1 = new String("").getClass();

       (2) Class類的靜態方法forName(),例:
            Class c2 = Class.forName(className);

        當使用Class.forName()方法時,必須提供完全限定類名。即類名要包括所有包名。

       (3) 使用類字面常量或TYPE字段,例:
            Class c3 = Manager.class;

            Class c4 = int.class;

            Class c5 = Double[].class;

        這種方式不僅更簡單,而且更安全,因爲它在編譯時就會受到檢查,並且根除了對forName方法的調用,也更高效,建議使用“.class”的形式
        TYPE是基本數據類型的包裝類型的一個標準字段,它是一個引用,指向對應的基本數據類型的Class對象,附表如下:     

boolean.class

Boolean.TYPE

char.class

Character.TYPE

byte.class

Byte.TYPE

short.class

Short.TYPE

int.class

Integer.TYPE

long.class

Long.TYPE

float.class

Float.TYPE

double.class

Double.TYPE

void.class

Void.TYPE

   

    使用Java反射,你可以在運行時檢查Java類。檢查類是使用反射時經常做的第一件事情。從類中可以獲取以下信息:

(1) 類名

(2) 類修飾符 (public, private, synchronized)

(3) 包信息

(4) 父類

(5) 實現的接口

(6) 構造函數

(7) 方法

(8) 字段

(9) 註解

(10) 內部類


    2.1 類名(getName(), getSimpleName())

    從Class對象中可以獲取兩個不同的類名。完全限定類名(包括包名)可以使用getName()getCanonicalName()方法獲取,例如:

        Class myClazz = MyObject.class;

        String className = myClazz.getName();

        String className1 = myClazz.getCanonicalName();

    如果想要獲取不含包名的類名可以使用getSimpleName() 方法,如下:

        String simpleClassName = myClazz.getSimpleName();


    2.2 修飾符(getModifiers())

    使用Class對象可以獲取一個類的修飾符類的修飾符即關鍵字"public","private", "static". 如下:

        int modifiers = myClazz.getModifiers();

    修飾符被包裝進一個int內,每一個修飾符都是一個標誌位(置位或清零)。可以使用java.lang.reflect.Modifier中的以下方法來檢驗修飾符:

        Modifier.isAbstract(int modifiers)

        Modifier.isFinal(int modifiers)

        Modifier.isInterface(int modifiers)

        Modifier.isNative(int modifiers)

        Modifier.isPrivate(int modifiers)

        Modifier.isProtected(int modifiers)

        Modifier.isPublic(int modifiers)

        Modifier.isStatic(int modifiers)

        Modifier.isStrict(int modifiers)

        Modifier.isSynchronized(int modifiers)

        Modifier.isTransient(int modifiers)

        Modifier.isVolatile(int modifiers)


    2.3 包信息(getPackage())

    使用Class對象可以獲取包信息java.lang.Package,如下:

        Package package = myClazz.getPackage();

        String packageName = package.getname();

    從Package對象中你可以訪問諸如名字等包信息。您還可以訪問類路徑上這個包位於JAR文件中Manifest這個文件中指定的信息。


    2.4 父類(getSuperclass())

    通過Class對象可以獲取類的父類,如下:

        Class superclass = myClazz.getSuperclass();

    父類的Class對象和其它Class對象一樣是一個Class對象,可以繼續使用反射。


    2.5 實現的接口(getInterfaces()), 只有給定類聲明實現的接口才會返回

    通過給定的類可以獲取這個類所實現的接口列表,如下:

        Class[] interfaces = myClazz.getInterfaces();

    一個類可以實現多個接口。因此返回一個Class數組。在Java反射機制中,接口也由Class對象表示。

    只有給定類聲明實現的接口才會返回。例如,如果類A的父類B實現了一個接口C,但類A並沒有聲明它也實現了C,那麼C不會被返回到數組中。即使類A實際上實現了接口C,因爲它的父類B實現了C。

    爲了得到一個給定的類實現接口的完整列表,需要遞歸訪問類和其超類。


    2.6 構造函數

//獲取一個公有的構造函數,參數爲指定參數
public Constructor<T> getConstructor (Class...<?> parameterTypes)
//獲取目標類所有的公有構造函數
public Constructor[]<?> getConstructors ()
// 獲取目標類的一個構造函數,參數爲指定參數
public Constructor<T> get
DeclaredConstructor (Class...<?> parameterTypes)
// 獲取目標類所有的公有構造函數
public Constructor[]<?> getDeclaredConstructors ()
    2.7 方法
    這裏需要注意的是 getDeclaredMethod 和 getDeclaredMethods 包含private、protected、default、public的函數,並且通過這兩個函數獲取到的只是在自身中定義的函數,也包括自己實現的接口,從父類和接口中繼承的函數不能夠獲取到。而 getMethod 和 getMethods 只包含 public 函數,父類和接口繼承的公有函數也能夠獲取到。

//獲取該類中的指定參數的某一方法, 可以是private、protected、default、public的, (不包含從父類和接口繼承的).
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)
//獲取該類中的所有函數(不包含從父類繼承的函數).
public Method[] getDeclaredMethods ()

//獲取該類指定參數的某一公有函數, (包含從父類和接口類繼承下來的)
public Method getMethod (String name, Class...<?> parameterTypes)
//
獲取該類所有公有函數, (包含從父類和接口類集成下來的函數)
public Method[] getMethods ()
    2.8 字段
    getDeclaredField 和 getDeclaredFields 包含 private、protected、default、public 的屬性,並且通過這兩個函數獲取到的只是在自身中定義的屬性,從父類中集成的屬性不能夠獲取到。而 getField 和 getFields 只包含 public 屬性,父類中的公有屬性也能夠獲取到。
// 獲取 Class 對象中指定屬性名的某一屬性
public Method getDeclaredField (String name)
// 獲取該 Class 對象中的所有屬性( 不包含從父類繼承的屬性 )
public Method[] getDeclaredFields ()
// 獲取指定的Class對象中指定屬性名的某一公有屬性
public Method getField (String name)
// 獲取該Class對象中的所有公有屬性 ( 包含從父類和接口類繼承下來的公有屬性 )
public Method[] getFields ()
    2.9 註解
// 獲取該類某一指定公有註解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
// 獲取該類所有公有註解
public Annotation[] getAnnotations()

// 獲取該類某一註解
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)

// 獲取該類所有註解
public Annotation[] getDeclaredAnnotations()

    2.10 內部類

// 獲取該類公有內部類(包含父類)
public Class<?>[] getClasses()
// 獲取該類所有內部類,包含私有內部類。
public Class<?>[] getDeclaredClasses()
// 獲取該類的外部類
public Class<?> getDeclaringClass()

    2.11 其它方法

// ([自身類.class]).isAssignableFrom([自身類.class]或[其子類.class])  返回true

isAssignableFrom(Class<?> cls)


// ([自身類.class]).isInstance([自身類的實例obj]或[其子類的實例obj])  返回true

isInstance(Object obj)

// 這裏不是Class成員方法,是一個運算符,放在這裏一起比較;
// [實例obj] instanceof [自身類、其父類、抽象類接口],右邊使用的是簡單類名,而不是Class。
instanceof

// 生成本類的對象,只能調用無參構造。我們使用new的時候,這個要new的類可以沒有加載。使用newInstance時候,就必須保證:1、這個類已經加載;2、這個類已經連接了。Class的靜態方法forName()調用了啓動類加載器(就是加載javaAPI的那個加載器)。newInstance實際上是把new這個方式分解爲兩步,即,首先調用class的加載方法加載某個類,然後實例化。這樣分步的好處是顯而易見的。我們可以在調用Class的靜態加載方法forName()時獲得更好的靈活性(傳入的className可以是從任何地方獲取的),提供給了我們降耦的手段。
newInstance()

// 返回當前clazz是否爲成員類;

isMemberClass()


// 返回當前類是否爲接口;
isInterface()


3. Constructor
// 返回當前Constructor實例所在的Class.
Class<TgetDeclaringClass()

// 返回當前Constructor實例參數個數.
int getParameterCount()

// 返回當前Constructor實例各參數對應的Class類型.
Class<?>[] getParameterTypes()

// 返回當前Constructor實例的各參數類型.
TypeVariable<Constructor<T>>[] getTypeParameters()

// 返回當前Constructor實例對應的方法修飾符.
int getModifiers()

// 返回當前方法名.
String getName()

// 使用當前Constructor實例構造一個該Constructor實例所在的Class的實例,相當於調用其對應參數個數的構造方法.
T newInstance(Object... initargs)


4. Field
// 返回指定對象obj上此Field對象表示的字段的值。
Object get(Object obj)

// 將指定對象變量obj上此Field對象表示的字段設置爲指定的新值。
void set(Object obj, Object value)

// 返回一個Class對象,它標識了此Field對象所表示字段的聲明類型。
Class<?> getType()

// 返回表示類或接口的Class對象,該類或接口聲明瞭由此Field對象表示的字段。
Class<?> getDeclaringClass()

// 返回此Field對象表示的字段的名稱。
String getName()

// 以整數形式返回由此Field對象表示的字段的 Java 語言修飾符。
int getModifiers()


5. Method
// 以指定參數調用obj對象的此Method所表示的方法。
Object invoke(Object obj, Object... args)

// 返回此Method實例參數個數.
int getParameterCount()

// 返回Method實例各參數對應的Class類型.
Class<?>[] getParameterTypes()

// 返回Method實例的各參數類型.
TypeVariable<Constructor<T>>[] getTypeParameters()

// 返回Method實例的返回值類型.
Class<?> getReturnType()

// 返回表示類或接口的Class對象,該類或接口聲明瞭由此Method對象表示的方法。
Class<?> getDeclaringClass()

// 返回此Method對象表示的方法的名稱。
String getName()

// 以整數形式返回由此Method對象表示的方法的 Java 語言修飾符。
int getModifiers()


6. Modifier
// 一個的修飾符的按位或組合, 參考Java Language Specification 8.1.1, 可能爲Annotation, public, protected, private, abstract, static, final, strictfp.
static int classModifiers()

// 一個構造函數修飾符的按位或組合,參考Java Language Specification 8.8.3, 可能爲Annotation, public, protected, private.
static int constructorModifiers()

// 一個成員變量修飾符的按位或組合,參考Java Language Specification 8.3.1, 可能爲Annotation, public, protected, private, static,final,transient,volatile.
static int fieldModifiers()

// 一個接口的修飾符的按位或組合, 參考Java Language Specification 9.1.1, 可能爲Annotation, public, protected, private, abstract, static, strictfp.
static int interfaceModifiers()

// 一個方法修飾符的按位或組合,參考Java Language Specification 8.4.3, 可能爲Annotation, public, protected, private, abstract, static, final,
synchronized,native, strictfp.
static int methodModifiers()

// 一個參數變量修飾符的按位或組合,參考Java Language Specification 8.4.1.
static int parameterModifiers()

abstract
static int ABSTRACT
static boolean isAbstract(int mod)
final
static int FINAL
static boolean isFinal(int mod)
interface
static int INTERFACE
static boolean isInterface(int mod)
native
static int NATIVE
static boolean isNative(int mod)
private
static int PRIVATE
static boolean isPrivate(int mod)
protect
static int PROTECT
static boolean isProtect(int mod)
public
static int PUBLIC
static boolean isPublic(int mod)
static
static int STATIC
static boolean isStatic(int mod)
strictfp
static int STRICT
static boolean isStrict(int mod)
synchronized
static int SYNCHRONIZED
static boolean isSynchronized(int mod)
transient
static int TRANSIENT
static boolean isTransient(int mod)
volatile
static int VOLATILE
static boolean isVolatile(int mod)


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