Java反射機制小結

1 Java反射機制概述

Reflection(反射)是被視爲動態語言的關鍵,反射機制允許程序在執行期藉助於Reflection API取得任何類內部信息,並能直接操作任意對象的內部屬性及方法

1.1 Java反射機制提供的功能

Ø運行時判斷任意一個對象所屬的

Ø運行時構造任意一個類的對象

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

Ø運行時調用任意一個對象的成員變量和方法

Ø生成動態代理

2.1 反射相關的主要API

Øjava.lang.Class:代表一個類

Øjava.lang.reflect.Method:代表類的方法

Øjava.lang.reflect.Field:代表類的成員變量

Øjava.lang.reflect.Constructor:代表類的構造方法

 

2 理解Class類並獲取Class類的實例

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

●  public final Class getClass()

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

2.1 Class類

對象照鏡子後可以得到的信息:某個的屬性、方法和構造器、某個類到底實現了哪些接口。對於每個類而言,JRE 爲其保留一個不變Class 類型的對象。一Class 對象包含了特定某個類的有關信息

Class本身也是一個類

Class 對象只能由系統建立對象

一個類JVM 只會有一個Class實例

一個Class對象對應的是一個加載到JVM中的一個.class文件

每個類的實例都會記得自己是由哪個 Class 實例所生成

通過Class可以完整地得到一個類中的完整結構

2.2 常用方法

方法名

功能說明

static Class  forName(String name)

返回指定類名 name Class 對象

Object newInstance()

調用缺省構造函數,返回該Class對象的一個實例

getName()

返回此Class對象所表示的實體(類、接口、數組類、基本類型或void)名稱

Class getSuperClass()

返回當前Class對象的父類的Class對象

Class [] getInterfaces()

獲取當前Class對象的接口

ClassLoader getClassLoader()

返回該類的類加載器

Class getSuperclass()

返回表示此Class所表示的實體的超類的Class

Constructor[] getConstructors()

返回一個包含某些Constructor對象的數組

Field[] getDeclaredFields()

返回Field對象的一個數組

Method getMethod(String name,Class  …  paramTypes)

返回一個Method對象,此對象的形參類型爲paramType

2.3 實例化Class類對象(四種方法)

1前提:若已知具體的類,通過類的class屬性獲取,該方法

                    最爲安全可靠,程序性能最高

       實例Class clazz = String.class;

2前提:已知某個類的實例,調用該實例的getClass()方法

                    Class對象

       實例:Class clazz = “www.yizhihanduxiu.com”.getClass();

3前提:已知一個類的全類名,且該類在類路徑下,可通過

       Class類的靜態方法forName()獲取,可能拋出ClassNotFoundException

       實例:Class clazz = Class.forName(“java.lang.String”);

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

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

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

3 類的加載與ClassLoader的理解

3.1 類的加載過程

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

3.2 ClassLoader

類加載器是用來把類(class)裝載進內存的JVM 規範定義了兩種類型的類加載器:啓動類加載(bootstrap)和用戶自定義加載(user-defined class loader)JVM在運行時會產生3個類加載器組成的初始化加載器層次結構 ,如下圖所示:

//1.獲取一個系統類加載器
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader);
//2.獲取系統類加載器的父類加載器,即擴展類加載器
classloader = classloader.getParent();
System.out.println(classloader);
//3.獲取擴展類加載器的父類加載器,即引導類加載器
classloader = classloader.getParent();
System.out.println(classloader);
//4.測試當前類由哪個類加載器進行加載
classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
System.out.println(classloader);
//5.測試JDK提供的Object類由哪個類加載器加載
classloader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classloader);
//*6.關於類加載器的一個主要方法:getResourceAsStream(String str):獲取類路徑下的指定文件的輸入流
InputStream in = null;
in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
System.out.println(in);

4 通過反射創建運行時類的對象

創建類的對象:調用Class對象的newInstance()方法

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

  2)類的構造器的訪問權限需要足夠。

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

不是!只要在操作的時候明確的調用類中的構造,並將參數傳遞進去之後,纔可以實例化操作。步驟如下:

1)通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構造器

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

3)  

//1.根據全類名獲取對應的Class對象
String name = “atguigu.java.Person";
Class clazz = null;
clazz = Class.forName(name);
//2.調用指定參數結構的構造器,生成Constructor的實例
Constructor con = clazz.getConstructor(String.class,Integer.class);
//3.通過Constructor的實例創建對應類的對象,並初始化類屬性
Person p2 = (Person) 	con.newInstance("Peter",20);
System.out.println(p2);

5 通過反射獲取運行時類的完整結構

1.實現的全部接口

Øpublic Class<?>[] getInterfaces()  

確定此對象所表示的類或接口實現的接口

2.所繼承的父類

Øpublic Class<? Super T> getSuperclass()

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

3.全部的構造

Øpublic Constructor<T>[] getConstructors()

返回Class 對象所表示的類的所有public構造方法

Øpublic Constructor<T>[] getDeclaredConstructors()

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

lConstructor類中

Ø取得修飾符: public int getModifiers();

Ø取得方法名稱: public String getName();

Ø取得參數的類型:public Class<?>[] getParameterTypes();

4.全部的方法

Øpublic Method[] getDeclaredMethods()

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

Øpublic Method[] getMethods() 

返回Class對象所表示的類或接口的public方法

lMethod類中:

Øpublic Class<?> getReturnType()取得全部的返回值

Øpublic Class<?>[] getParameterTypes()取得全部的參數

Øpublic int getModifiers()取得修飾符

Øpublic Class<?>[] getExceptionTypes()取得異常信息

5.全部Field

Øpublic Field[] getFields()

返回Class對象所表示的類或接口的publicField

Øpublic Field[] getDeclaredFields()

返回Class對象所表示的類或接口的全部Field

lField方法中:

Øpublic int getModifiers()  以整數形式返回此Field的修飾符

Øpublic Class<?> getType()  得到Field的屬性類型

Øpublic String getName()  返回Field的名稱。

6. Annotation相關

Øget Annotation(Class<T> annotationClass)

ØgetDeclaredAnnotations()

7.泛型相關

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

泛型類型:ParameterizedType

獲取實際的泛型類型參數數組:getActualTypeArguments()

8.類所在的包    Package getPackage()

6 通過反射調用運行時類的指定屬性、指定方法等

6.1 調用指定方法

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

1.通過Class類的getMethod(String name,Class…parameterTypes)方法取得一個Method對象,並設置此方法操作時所需要的參數類型。

2.之後使用Object invoke(Object obj, Object[] args)進行調用,並向方法中傳遞要設置的obj對象的參數信息。

Object invoke(Object obj, Object …  args)

說明:

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

    2.若原方法若爲靜態方法,此時形參Object obj可爲null

    3.若原方法形參列表爲空,則Object[] argsnull

    4.若原方法聲明爲private,則需要在調用此invoke()方法前,顯式調用方法對象的setAccessible(true)方法,將可訪問private的方法。

6.2 調用指定屬性

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

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

Ø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)訪問私有屬性時,讓這個屬性可見。

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