Java讀書筆記07 反射


 

Java中的反射

  本文為反射的基礎知識部分。

  能夠分析類能力的程序被稱為反射(reflective)。

  反射機制允許程序在運行時取得任何一個已知名稱的class的內部信息,容許程序在運行時加載、探知、使用編譯期間未知的class。即Java的反射機制可以加載一個運行時才得知名稱的class,獲得其完整結構。

 

一.Class類

  在程序運行期間,Java運行時系統始終為所有的對象維護一個被稱為運行時的類型標識。

  這個信息保存着每個對象所屬的類足跡。虛擬機利用運行時信息選擇相應的方法執行。

  然而,可以通過專門的Java類訪問這些信息。保存這些信息的類稱為Class.

  (注:新版本為Class<T>,本文中經常為了方便只寫Class)

  API: java.lang.Class

  (1.7)http://docs.oracle.com/javase/7/docs/api/index.html

 

   獲取類的Class對象的方法:

調用getClass()

(Object類中的getClass()方法返回一個Class類型的實例)

Boolean var1 = true;Class<?> classType2 = var1.getClass();System.out.println(classType2);輸出:class java.lang.Boolean 

運用T.class 語法

(T是任意的Java類型)

Class<?> classType4 = Boolean.class;System.out.println(classType4);輸出:class java.lang.Boolean 

運用static method Class.forName()

(使用時應該提供異常處理器)

Class<?> classType5 = Class.forName("java.lang.Boolean");System.out.println(classType5);輸出:class java.lang.Boolean 

運用primitive wrapper classes的TYPE 語法

(這里返回的是原生類型,和Boolean.class返回的不同)

Class<?> classType3 = Boolean.TYPE;System.out.println(classType3);輸出:boolean 

  一個Class對象實際上表示的是一個類型,而這個類型未必一定是一種類。

  例如,int不是類,但int.class是一個Class類型的對象。

  擬機為每個類型管理一個Class對象。因此,可以用==運算符實現兩個類對象比較的操作。

 

  最常用的Class方法:

方法

說明

例子

getName()

 

返回類的名字

String.class.getName();

返回: "java.lang.String"

newInstance()

 

快速地創建一個類的實例

(調用默認構造器,如果該類沒有默認構造器,拋出異常)

(如果要為構造器提供參數,使用java.lang.reflect.Constructor中的newInstance方法)

String s = "java.util.Date";

Object m = Class.forName(s).newInstance();

getSuperclass()

返回超類

 

getFields()getMethods()getConstructors()(還有帶字符串參數,給定名稱的形式)

 

分別返回類支持的public、方法和構造器數組,其中包括超類的公有成員

 

getDeclaredFields()

getDeclaredMethods()

getDeclaredConstructors()

(還有給定名稱的形式)

 

分別返回類中聲明的全部域、方法和構造器數組。其中包括私有和保護成員,但不包括超類的成員

 

 

二.java.lang.reflect包

  上文中提到的Class類中的getFields()、getMethods()、getConstructors()方法的返回值都是特定類型(Field、Method、Constructor類的數組類型。

  Field、Method、Constructor類,分別用於描述類的域、方法和構造器,都在java.lang.reflect包中。

  java.lang.reflect包提供反射相關的API,1.7.0的reflect包如下圖:

  (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-frame.html

 

  2.1使用反射分析類

  如前所述,Field、Method、Constructor類,分別用於描述類的域、方法和構造器。另外java.lang.reflect包中的Modifier類可以分析訪問修飾符。那么用它們就可以分析類。

  分析類常用的方法:

方法 作用
FieldMethodConstructor Class getDeclaringClass() 返回一個用於描述類中定義的構造器、方法或域的Class對象
String getName() 返回相應條目的名稱
int getModifiers() 返回整型數值,用不同的位開關描述訪問修飾符的使用狀況

Method

Constructor

Class[] getExceptionTypes()

返回一個用於描述方法拋出的異常類型的Class對象數組

Class[] getParameterTypes()

返回一個用於描述參數類型的Class對象數組

Field

Class getType()

用於返回描述域所屬類型的Class類型對象

Modifier

static String toString(int modifiers)

返回對應modifiers位設置的修飾符的字符串表示

Static boolean isXXX(int modifiers)

檢測方法名中對應的修飾符在modifiers中的值

 

  2.2使用反射分析對象

  2.1節已經知道如何查看任意對象的數據域名稱和類型,在本節中,將進一步查看數據域的實際內容。利用反射機制可以查看在編譯時還不清楚的對象域。

 

  查看對象域的關鍵方法是Field類中的get方法。

  如果f是一個Field類型的對象(例如,通過getField(String name)得到的對象),obj是某個包含f域的類的對象,那么f.get(obj)將返回一個對象,其值為obj的f域的當前值。

  可以獲取就可以設置,調用f.set(obj,value)可以將obj對象的f域設置成新值。

  訪問權限問題

  上面所說的例子中,如果該域為一個私有域,get方法將會拋出一個異常。

 

  這是因為反射機制的默認行為受限於Java的訪問控制,比如,除非擁有訪問權限,否則Java安全機制允許查看任意對象有哪些域,而不允許讀它們的值。

  然而如果一個Java程序沒有受到安全管理器的控制,就可以覆蓋訪問控制。為了達到這個目的,就需要調用Field、Method、Constructor對象的setAccessible方法。

 

  Field、Method、Constructor類都派生自AccessibleObject.

  AccessibleObject常用方法:

函數

作用

void setAccessible(boolean flag)

為反射對象設置可訪問標志,flag為true表明屏蔽Java語言的訪問檢查,使得對象的私有屬性也可以被查詢和設置

boolean isAccessible()

返回反射對象的可訪問標志的值

static void setAccessible(AccessibleObject[] array, boolean flag)

一種設置對象數組可訪問標志的快捷方法

 

三.資源

  本文主要參考《JAVA 2核心技術 卷Ⅰ》第五章有關內容。

  書中代碼下載地址:http://horstmann.com/corejava.html

 

  API文檔地址http://docs.oracle.com/javase/7/docs/api/index.html

 

  另外關於反射,比較有用的幾個博客鏈接:

http://www.blogjava.net/jialing/archive/2006/08/24/JavaReflectionCookbook1.html

http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

http://www.cnblogs.com/Quincy/archive/2011/06/19/2084557.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM