Java 反射機制
什么是反射
Java 反射是Java語言的一個很重要的特征,它使得Java具體了“動態(tài)性”。
反射主要是指程序可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。在計算機科學領域,反射是一類應用,它們能夠自描述和自控制。這類應用通過某種機制來實現(xiàn)對自己行為的描述和檢測,并能根據(jù)自身行為的狀態(tài)和結果,調整或修改應用所描述行為的狀態(tài)和相關的語義。
在Java中的反射機制,被稱為Reflection。(大家看到這個單詞,第一個想法應該就是去開發(fā)文檔中搜一下了。)它允許運行中的Java程序對自身進行檢查,并能直接操作程序的內部屬性或方法。Reflection機制允許程序在正在執(zhí)行的過程中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在執(zhí)行的過程中,動態(tài)生成Instances、變更fields內容或喚起methods。
Java 反射機制主要提供了以下功能
在運行時判斷任意一個對象所屬的類。
在運行時構造任意一個類的對象。
在運行時判斷任意一個類所具有的成員變量和方法。
在運行時調用任意一個對象的方法。
簡單應用
- 通過Class類獲取成員變量、成員方法、接口、超類、構造方法等
運行時復制對象
用反射機制調用對象的方法
動態(tài)創(chuàng)建和訪問數(shù)組
運行時變更field內容
Java 反射
核心類,位于java.lang.reflect包中
Class類:代表一個類。
Field 類:代表類的成員變量(成員變量也稱為類的屬性)。
Method類:代表類的方法。
Constructor 類:代表類的構造方法。
Array類:提供了動態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組的元素的靜態(tài)方法。
核心 API
在 java.lang.Object 類中定義了getClass()方法,因此對于任意一個Java對象,都可以通過此方法獲得對象的類型。
獲取類的完整名字
- public String getName() :獲得類的完整名字。
獲取構造方法
Constructor getConstructor(Class[] params) 根據(jù)構造函數(shù)的參數(shù),返回一個具體的具有public屬性的構造函數(shù)
Constructor getConstructors() 返回所有具有public屬性的構造函數(shù)數(shù)組
Constructor getDeclaredConstructor(Class[] params) 根據(jù)構造函數(shù)的參數(shù),返回一個具體的構造函數(shù)(不分public和非public屬性)
Constructor getDeclaredConstructors() 返回該類中所有的構造函數(shù)數(shù)組(不分public和非public屬性)
獲取類的成員方法
Method getMethod(String name, Class[] parameterTypes) 根據(jù)方法名和參數(shù),返回一個具體的具有public屬性的方法
Method[] getMethods() 返回所有具有public屬性的方法數(shù)組
Method getDeclaredMethod(String name, Class[] params) 根據(jù)方法名和參數(shù),返回一個具體的方法(不分public和非public屬性)
Method[] getDeclaredMethods() 返回該類中的所有的方法數(shù)組(不分public和非public屬性),不包含繼承來的方法
獲取類的成員變量(成員屬性)
Field getField(String name) 根據(jù)變量名,返回一個具體的具有public屬性的成員變量
Field[] getFields() 返回具有public屬性的成員變量的數(shù)組
Field getDeclaredField(String name) 根據(jù)變量名,返回一個成員變量(不分public和非public屬性)
Field[] getDelcaredField() 返回所有成員變量組成的數(shù)組(不分public和非public屬性)
獲取類、屬性、方法的修飾域
類Class、Method、Constructor、Field都有一個public方法int getModifiers()。該方法返回一個int類型的數(shù),表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。
//打印輸出方法的修飾域
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod) + "");
創(chuàng)建類的一個實例
// 利用newInstance()方法,獲取構造方法的實例
Object obj = cls.newInstance();
// Class的newInstance方法,僅提供默認無參的實例化方法,類似于無參的構造方法
// Constructor的newInstance方法,提供了帶參數(shù)的實例化方法,類似于含參的構造方法
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
調用方法
public Object invoke(Object obj, Object... args) 調用靜態(tài)方法時,第一個參數(shù)為 null
public void setAccessible(boolean flag) 可以改變私有方法的權限
原理
java虛擬機有一個運行時數(shù)據(jù)區(qū),這個數(shù)據(jù)區(qū)又被分為方法區(qū),堆區(qū)和棧區(qū),我們這里需要了解的主要是方法區(qū)。方法區(qū)的主要作用是存儲被裝載的類的類型信息,當java虛擬機裝載某個類型的時候,需要類裝載器定位相應的class文件,然后將其讀入到java虛擬機中,緊接著虛擬機提取class中的類型信息,將這些信息存儲到方法區(qū)中。這些信息主要包括:
這個類型的全限定名
這個類型的直接超類的全限定名
這個類型是類類型還是接口類型
這個類型的訪問修飾符
任何直接超接口的全限定名的有序列表
該類型的常量池
字段信息
方法信息
除了常量以外的所有類變量
一個到class類的引用
應用
解析 Json 格式數(shù)據(jù),并利用反射創(chuàng)建對應對象
利用反射調用私有方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethodEx {
/**
* 在運行時加載指定的類,并調用指定的方法
* @param cName Java的類名
* @param MethodName 方法名
* @param params 方法的參數(shù)值
* @return
*/
public Object Load(String cName, String MethodName, Object[] params) {
Object retObject = null;
try {
// 加載指定的類
Class cls = Class.forName(cName); // 獲取Class類的對象的方法之二
// 利用newInstance()方法,獲取構造方法的實例
// Class的newInstance方法只提供默認無參構造實例
// Constructor的newInstance方法提供帶參的構造實例
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
//Object obj = cls.newInstance();
// 根據(jù)方法名獲取指定方法的參數(shù)類型列表
Class paramTypes[] = this.getParamTypes(cls, MethodName);
// 獲取指定方法
Method meth = cls.getMethod(MethodName, paramTypes);
meth.setAccessible(true);
// 調用指定的方法并獲取返回值為Object類型
retObject = meth.invoke(obj, params);
} catch (Exception e) {
System.err.println(e);
}
return retObject;
}
/**
* 獲取參數(shù)類型,返回值保存在Class[]中
*/
public Class[] getParamTypes(Class cls, String mName) {
Class[] cs = null;
/*
* Note: 由于我們一般通過反射機制調用的方法,是非public方法
* 所以在此處使用了getDeclaredMethods()方法
*/
Method[] mtd = cls.getDeclaredMethods();
for (int i = 0; i < mtd.length; i++) {
if (!mtd[i].getName().equals(mName)) { // 不是我們需要的參數(shù),則進入下一次循環(huán)
continue;
}
cs = mtd[i].getParameterTypes();
}
return cs;
}
}
參考:
http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014582.html
http://lavasoft.blog.51cto.com/62575/43218