天天看點

Java反射機制

Reflection(反射)是被視為動态語言的關鍵,反射機制允許程式在執行期借助于Reflection API取得任何類的内部資訊,并能直接操作任意對象的内部屬性及方法。

1、 Java 反射機制提供的功能

在運作時判斷任意一個對象所屬的類。

在運作時構造任意一個類的對象。

在運作時判斷任意一個類所具有的成員變量和方法。

在運作時調用任意一個對象的成員變量和方法。

生成動态代理。

2、在Object類中定義了以下的方法,此方法将被所有子類繼承:

public final Class getClass()

以上的方法傳回值的類型是一個Class類,此類是Java反射的源頭,實際上所謂反射從程式的運作結果來看也很好了解,即:可以通過對象反射求出類的名稱。

1) 前提:若已知具體的類,通過類的class屬性擷取,該方法最為安全可靠,程式性能最高。

執行個體:Class clazz = String.class;

2) 前提:已知某個類的執行個體,調用該執行個體的getClass()方法擷取Class對象。

執行個體:Class clazz = “www.atguigu.com”.getClass();

3) 前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜态方法forName()擷取,可能抛出

ClassNotFoundException。

執行個體:Class clazz = Class.forName(“java.lang.String”);

4)其他方式(不做要求)

ClassLoader cl = this.getClass().getClassLoader();

Class clazz4 = cl.loadClass(“類的全類名”);

當程式主動使用某個類時,如果該類還未被加載到記憶體中,則系統會通過如下三個步驟來對該類進行初始化。

Java反射機制
Java反射機制

2.1. 建立類的對象:調用Class對象的newInstance()方法

要 求:1)類必須有一個無參數的構造器。

2)類的構造器的通路權限需要足夠。

難道沒有無參的構造器就不能建立對象了嗎?

不是!隻要在操作的時候明确的調用類中的構造方法,并将參數傳遞進去之後,才可以執行個體化操作。步驟如下:

1)通過Class類的getDeclaredConstructor(Class … parameterTypes)

取得本類的指定形參類型的構造器

2)向構造器的形參中傳遞一個對象數組進去,裡面包含了構造器中所需的各個參數。

3)通過Constructor執行個體化對象。

有了 有了Class對象,能做什麼? 對象,能做什麼?

Java反射機制

以上是反射機制應用最多的地方。

使用反射可以取得:

1.實作的全部接口 實作的全部接口

确定此對象所表示的類或接口實作的接口。

2.所繼承的父類 所繼承的父類

傳回表示此 Class 所表示的實體(類、接口、基本類型)的父類的 Class。

3.全部的構造器 全部的構造器

傳回此 Class 對象所表示的類的所有public構造方法。

傳回此 Class 對象表示的類聲明的所有構造方法。

Constructor類中:

取得修飾符: <code>public int getModifiers();</code>

取得方法名稱: <code>public String getName();</code>

取得參數的類型:<code>public Class&lt;?&gt;[] getParameterTypes();</code>

4.全部的方法 全部的方法

傳回此Class對象所表示的類或接口的全部方法。

傳回此Class對象所表示的類或接口的public的方法。

Method類中:

<code>public Class&lt;?&gt; getReturnType()</code>取得全部的傳回值。

<code>public Class&lt;?&gt;[] getParameterTypes()</code>取得全部的參數。

<code>public int getModifiers()</code>取得修飾符。

<code>public Class&lt;?&gt;[] getExceptionTypes()</code>取得異常資訊。

5. 全部的Field

傳回此Class對象所表示的類或接口的public的Field。

傳回此Class對象所表示的類或接口的全部Field。

lField方法中:

<code>這裡寫代碼片</code>public int getModifiers() 以整數形式傳回此Field的修飾符。

<code>public Class&lt;?&gt; getType()</code> 得到Field的屬性類型。

<code>public String getName()</code> 傳回Field的名稱。

6. Annotation相關 相關

7.泛型相關 泛型相關

擷取父類泛型類型:Type getGenericSuperclass()

泛型類型:ParameterizedType

擷取實際的泛型類型參數數組:

getActualTypeArguments()

8. 類所在的包 Package getPackage()

通過反射,調用類中的方法,通過Method類完成。步驟:

1.通過Class類的getMethod(String name,Class…parameterTypes)方

法取得一個Method對象,并設定此方法操作時所需要的參數類型。

2.之後使用Object invoke(Object obj, Object[] args)進行調用,并向

方法中傳遞要設定的obj對象的參數資訊。

說明:

1.Object 對應原方法的傳回值,若原方法無傳回值,此時傳回null。

2.若原方法若為靜态方法,此時形參Object obj可為null。

3.若原方法形參清單為空,則Object[] args為null。

4.若原方法聲明為private,則需要在調用此invoke()方法前,顯式調用方法對象的setAccessible(true)方法,将可通路private的方法。

在反射機制中,可以直接通過Field類操作類中的屬性,通過Field類提供的set()和get()方法就可以完成設定和取得屬性内容的操作。

public Field getField(String name) 傳回此Class對象表示的類或接口的指定的public的Field。

public Field getDeclaredField(String name)傳回此Class對象表示的類或接口的指定的Field。

在 在Field中:

public Object get(Object obj) 取得指定對象obj上此Field的屬性内容。

public void set(Object obj,Object value) 設定指定對象obj上此Field的屬性内容。

注:在類中屬性都設定為private的前提下,在使用set()和get()方法時,首先要使用Field類中的setAccessible(true)方法将需要操作的屬性設定為可以被外部通路。

public void setAccessible(true)通路私有屬性時,讓這個屬性可見。