Java 反射機(jī)制
什么是反射
Java 反射是Java語(yǔ)言的一個(gè)很重要的特征族淮,它使得Java具體了“動(dòng)態(tài)性”受神。
反射主要是指程序可以訪(fǎng)問(wèn)卵慰、檢測(cè)和修改它本身狀態(tài)或行為的一種能力抬吟。在計(jì)算機(jī)科學(xué)領(lǐng)域渐行,反射是一類(lèi)應(yīng)用弛针,它們能夠自描述和自控制叠骑。這類(lèi)應(yīng)用通過(guò)某種機(jī)制來(lái)實(shí)現(xiàn)對(duì)自己行為的描述和檢測(cè),并能根據(jù)自身行為的狀態(tài)和結(jié)果削茁,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語(yǔ)義宙枷。
在Java中的反射機(jī)制,被稱(chēng)為Reflection茧跋。(大家看到這個(gè)單詞慰丛,第一個(gè)想法應(yīng)該就是去開(kāi)發(fā)文檔中搜一下了。)它允許運(yùn)行中的Java程序?qū)ψ陨磉M(jìn)行檢查瘾杭,并能直接操作程序的內(nèi)部屬性或方法诅病。Reflection機(jī)制允許程序在正在執(zhí)行的過(guò)程中,利用Reflection APIs取得任何已知名稱(chēng)的類(lèi)的內(nèi)部信息,包括:package贤笆、 type parameters蝇棉、 superclass、 implemented interfaces芥永、 inner classes银萍、 outer classes、 fields恤左、 constructors贴唇、 methods、 modifiers等飞袋,并可以在執(zhí)行的過(guò)程中戳气,動(dòng)態(tài)生成Instances、變更fields內(nèi)容或喚起methods巧鸭。
Java 反射機(jī)制主要提供了以下功能
在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類(lèi)瓶您。
在運(yùn)行時(shí)構(gòu)造任意一個(gè)類(lèi)的對(duì)象。
在運(yùn)行時(shí)判斷任意一個(gè)類(lèi)所具有的成員變量和方法纲仍。
在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法呀袱。
簡(jiǎn)單應(yīng)用
- 通過(guò)Class類(lèi)獲取成員變量、成員方法郑叠、接口夜赵、超類(lèi)、構(gòu)造方法等
運(yùn)行時(shí)復(fù)制對(duì)象
用反射機(jī)制調(diào)用對(duì)象的方法
動(dòng)態(tài)創(chuàng)建和訪(fǎng)問(wèn)數(shù)組
運(yùn)行時(shí)變更field內(nèi)容
Java 反射
核心類(lèi)乡革,位于java.lang.reflect包中
Class類(lèi):代表一個(gè)類(lèi)寇僧。
Field 類(lèi):代表類(lèi)的成員變量(成員變量也稱(chēng)為類(lèi)的屬性)。
Method類(lèi):代表類(lèi)的方法沸版。
Constructor 類(lèi):代表類(lèi)的構(gòu)造方法嘁傀。
Array類(lèi):提供了動(dòng)態(tài)創(chuàng)建數(shù)組,以及訪(fǎng)問(wèn)數(shù)組的元素的靜態(tài)方法视粮。
核心 API
在 java.lang.Object 類(lèi)中定義了getClass()方法细办,因此對(duì)于任意一個(gè)Java對(duì)象,都可以通過(guò)此方法獲得對(duì)象的類(lèi)型蕾殴。
獲取類(lèi)的完整名字
- public String getName() :獲得類(lèi)的完整名字笑撞。
獲取構(gòu)造方法
Constructor getConstructor(Class[] params) 根據(jù)構(gòu)造函數(shù)的參數(shù),返回一個(gè)具體的具有public屬性的構(gòu)造函數(shù)
Constructor getConstructors() 返回所有具有public屬性的構(gòu)造函數(shù)數(shù)組
Constructor getDeclaredConstructor(Class[] params) 根據(jù)構(gòu)造函數(shù)的參數(shù)区宇,返回一個(gè)具體的構(gòu)造函數(shù)(不分public和非public屬性)
Constructor getDeclaredConstructors() 返回該類(lèi)中所有的構(gòu)造函數(shù)數(shù)組(不分public和非public屬性)
獲取類(lèi)的成員方法
Method getMethod(String name, Class[] parameterTypes) 根據(jù)方法名和參數(shù)娃殖,返回一個(gè)具體的具有public屬性的方法
Method[] getMethods() 返回所有具有public屬性的方法數(shù)組
Method getDeclaredMethod(String name, Class[] params) 根據(jù)方法名和參數(shù)值戳,返回一個(gè)具體的方法(不分public和非public屬性)
Method[] getDeclaredMethods() 返回該類(lèi)中的所有的方法數(shù)組(不分public和非public屬性),不包含繼承來(lái)的方法
獲取類(lèi)的成員變量(成員屬性)
Field getField(String name) 根據(jù)變量名议谷,返回一個(gè)具體的具有public屬性的成員變量
Field[] getFields() 返回具有public屬性的成員變量的數(shù)組
Field getDeclaredField(String name) 根據(jù)變量名,返回一個(gè)成員變量(不分public和非public屬性)
Field[] getDelcaredField() 返回所有成員變量組成的數(shù)組(不分public和非public屬性)
獲取類(lèi)堕虹、屬性卧晓、方法的修飾域
類(lèi)Class芬首、Method、Constructor逼裆、Field都有一個(gè)public方法int getModifiers()郁稍。該方法返回一個(gè)int類(lèi)型的數(shù),表示被修飾對(duì)象( Class胜宇、 Method耀怜、 Constructor、 Field )的修飾類(lèi)型的組合值桐愉。
//打印輸出方法的修飾域
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod) + "");
創(chuàng)建類(lèi)的一個(gè)實(shí)例
// 利用newInstance()方法财破,獲取構(gòu)造方法的實(shí)例
Object obj = cls.newInstance();
// Class的newInstance方法,僅提供默認(rèn)無(wú)參的實(shí)例化方法从诲,類(lèi)似于無(wú)參的構(gòu)造方法
// Constructor的newInstance方法左痢,提供了帶參數(shù)的實(shí)例化方法,類(lèi)似于含參的構(gòu)造方法
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
調(diào)用方法
public Object invoke(Object obj, Object... args) 調(diào)用靜態(tài)方法時(shí)系洛,第一個(gè)參數(shù)為 null
public void setAccessible(boolean flag) 可以改變私有方法的權(quán)限
原理
java虛擬機(jī)有一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)俊性,這個(gè)數(shù)據(jù)區(qū)又被分為方法區(qū),堆區(qū)和棧區(qū)描扯,我們這里需要了解的主要是方法區(qū)定页。方法區(qū)的主要作用是存儲(chǔ)被裝載的類(lèi)的類(lèi)型信息,當(dāng)java虛擬機(jī)裝載某個(gè)類(lèi)型的時(shí)候绽诚,需要類(lèi)裝載器定位相應(yīng)的class文件拯勉,然后將其讀入到j(luò)ava虛擬機(jī)中,緊接著虛擬機(jī)提取class中的類(lèi)型信息憔购,將這些信息存儲(chǔ)到方法區(qū)中宫峦。這些信息主要包括:
這個(gè)類(lèi)型的全限定名
這個(gè)類(lèi)型的直接超類(lèi)的全限定名
這個(gè)類(lèi)型是類(lèi)類(lèi)型還是接口類(lèi)型
這個(gè)類(lèi)型的訪(fǎng)問(wèn)修飾符
任何直接超接口的全限定名的有序列表
該類(lèi)型的常量池
字段信息
方法信息
除了常量以外的所有類(lèi)變量
一個(gè)到class類(lèi)的引用
應(yīng)用
解析 Json 格式數(shù)據(jù),并利用反射創(chuàng)建對(duì)應(yīng)對(duì)象
利用反射調(diào)用私有方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethodEx {
/**
* 在運(yùn)行時(shí)加載指定的類(lèi)玫鸟,并調(diào)用指定的方法
* @param cName Java的類(lèi)名
* @param MethodName 方法名
* @param params 方法的參數(shù)值
* @return
*/
public Object Load(String cName, String MethodName, Object[] params) {
Object retObject = null;
try {
// 加載指定的類(lèi)
Class cls = Class.forName(cName); // 獲取Class類(lèi)的對(duì)象的方法之二
// 利用newInstance()方法导绷,獲取構(gòu)造方法的實(shí)例
// Class的newInstance方法只提供默認(rèn)無(wú)參構(gòu)造實(shí)例
// Constructor的newInstance方法提供帶參的構(gòu)造實(shí)例
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
//Object obj = cls.newInstance();
// 根據(jù)方法名獲取指定方法的參數(shù)類(lèi)型列表
Class paramTypes[] = this.getParamTypes(cls, MethodName);
// 獲取指定方法
Method meth = cls.getMethod(MethodName, paramTypes);
meth.setAccessible(true);
// 調(diào)用指定的方法并獲取返回值為Object類(lèi)型
retObject = meth.invoke(obj, params);
} catch (Exception e) {
System.err.println(e);
}
return retObject;
}
/**
* 獲取參數(shù)類(lèi)型,返回值保存在Class[]中
*/
public Class[] getParamTypes(Class cls, String mName) {
Class[] cs = null;
/*
* Note: 由于我們一般通過(guò)反射機(jī)制調(diào)用的方法屎飘,是非public方法
* 所以在此處使用了getDeclaredMethods()方法
*/
Method[] mtd = cls.getDeclaredMethods();
for (int i = 0; i < mtd.length; i++) {
if (!mtd[i].getName().equals(mName)) { // 不是我們需要的參數(shù)妥曲,則進(jìn)入下一次循環(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