花了幾天時間,研究了一下Java的反射機制。在這裏總結一下這幾天學習的成果,一來分享本身的學習過程和在學習中遇到的問題,二來是給像我同樣不太瞭解Java反射機制的同窗作一個簡單的介紹。在文章後面會連接一個Android反射機制的應用程序。html
1、反射的概念及在Java中的類反射java
反射主要是指程序能夠訪問、檢測和修改它自己狀態或行爲的一種能力。在計算機科學領域,反射是一類應用,它們可以自描述和自控制。這類應用經過某種機制來實現對本身行爲的描述和檢測,並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。android
在Java中的反射機制,被稱爲Reflection。(你們看到這個單詞,第一個想法應該就是去開發文檔中搜一下了。)它容許運行中的Java程序對自身進行檢查,並能直接操做程序的內部屬性或方法。Reflection機制容許程序在正在執行的過程當中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,並能夠在執行的過程當中,動態生成Instances、變動fields內容或喚起methods。數組
好,瞭解這些,那咱們就知道了,咱們能夠利用反射機制在Java程序中,動態的去調用一些protected甚至是private的方法或類,這樣能夠很大程度上知足咱們的一些比較特殊需求。你固然會問,反射機制在Android平臺下有何用處呢?安全
咱們在進行Android程序的開發時,爲了方便調試程序,並快速定位程序的錯誤點,會從網上下載到對應版本的Android SDK的源碼(這裏給你們提供一個2.3.3版本的下載連接)。你會發現不少類或方法中常常加上了「@hide」註釋標記,它的做用是使這個方法或類在生成SDK時不可見,那麼咱們的程序可能沒法編譯經過,並且在最終發佈的時候,就可能存在一些問題。app
那麼,對於這個問題,第一種方法就是本身去掉Android源碼中的"@hide"標記,而後從新編譯生成一個SDK。另外一種方法就是使用Java反射機制了,能夠利用這種反射機制訪問存在訪問權限的方法或修改其域。ide
廢話半天,該入正題了,在進入正題以前,先給上一個反射測試類的代碼,該代碼中定義了咱們須要進行反射的類,該類並無實際的用途,僅供作爲測試類。提示:本文提供的代碼,並非Android平臺下的代碼,而是一個普通的Java程序,僅僅是對Java反射機制的Demo程序,因此你們不要放在Android下編譯啊,不然出現問題,別追究個人責任啦!函數
ReflectionTest.java學習
package crazypebble.reflectiontest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
public class ReflectionTest extends Object implements ActionListener,Serializable{
// 成員變量
private int bInt;
public Integer bInteger = new Integer(4);
public String strB = "crazypebble";
private String strA;
// 構造函數
public ReflectionTest() {
}
protected ReflectionTest(int id, String name) {
}
// 成員方法
public int abc(int id, String name) {
System.out.println("crazypebble ---> " + id + "-" + name);
return 0;
}
protected static void edf() {
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}測試
2、反射機制中須要使用到的類
我把須要使用的類列在下表中,其中對咱們特別有用的類,經過着重標記顯示出來,並將在後面的使用中逐步解釋:
3、Class類
首先向你們說明一點,Class自己就是一個類,Class是該類的名稱。看如下下面這個類的定義:
public class MyButton extends Button {...}
注意到上面的class的首字母是小寫,它表示的是一種類類型,可是咱們的Class是一個類,至關於上面定義的MyButton類。因此,千萬不要把這裏的Class作爲一個類類型來理解。明白這一點,咱們繼續。
Class類是整個Java反射機制的源頭,Class類自己表示Java對象的類型,咱們可經過一個Object對象的getClass()方法取得一個對象的類型,此函數返回的就是一個Class類。獲取Class對象的方法有不少種:
在平時的使用,要注意對這幾種方法的靈活運用,尤爲是對Class.forName()方法的使用。由於在不少開發中,會直接經過類的名稱取得Class類的對象。
4、獲取類的相關信息
一、獲取構造方法
Class類提供了四個public方法,用於獲取某個類的構造方法。
Constructor getConstructor(Class[] params) 根據構造函數的參數,返回一個具體的具備public屬性的構造函數
Constructor getConstructors() 返回全部具備public屬性的構造函數數組
Constructor getDeclaredConstructor(Class[] params) 根據構造函數的參數,返回一個具體的構造函數(不分public和非public屬性)
Constructor getDeclaredConstructors() 返回該類中全部的構造函數數組(不分public和非public屬性)
因爲Java語言是一種面向對象的語言,具備多態的性質,那麼咱們能夠經過構造方法的參數列表的不一樣,來調用不一樣的構造方法去建立類的實例。一樣,獲取不一樣的構造方法的信息,也須要提供與之對應的參數類型信息;所以,就產生了以上四種不一樣的獲取構造方法的方式。
get_Reflection_Constructors()
/**
* 獲取反射類中的構造方法
* 輸出打印格式:"Modifier修飾域 構造方法名(參數類型列表)"
*/
public static void get_Reflection_Constructors(ReflectionTest r) {
Class temp = r.getClass();
String className = temp.getName(); // 獲取指定類的類名
try {
Constructor[] theConstructors = temp.getDeclaredConstructors(); // 獲取指定類的公有構造方法
for (int i = 0; i < theConstructors.length; i++) {
int mod = theConstructors[i].getModifiers(); // 輸出修飾域和方法名稱
System.out.print(Modifier.toString(mod) + " " + className + "(");
Class[] parameterTypes = theConstructors[i].getParameterTypes(); // 獲取指定構造方法的參數的集合
for (int j = 0; j < parameterTypes.length; j++) { // 輸出打印參數列表
System.out.print(parameterTypes[j].getName());
if (parameterTypes.length > j+1) {
System.out.print(", ");
}
}
System.out.println(")");
}
} catch (Exception e) {
e.printStackTrace();
}
}
二、獲取類的成員方法
與獲取構造方法的方式相同,存在四種獲取成員方法的方式。
Method getMethod(String name, Class[] params) 根據方法名和參數,返回一個具體的具備public屬性的方法
Method[] getMethods() 返回全部具備public屬性的方法數組
Method getDeclaredMethod(String name, Class[] params) 根據方法名和參數,返回一個具體的方法(不分public和非public屬性)
Method[] getDeclaredMethods() 返回該類中的全部的方法數組(不分public和非public屬性)
get_Reflection_Method()
/**
* 獲取反射類的方法
* 打印輸出格式:"RetType FuncName(paramTypeList)"
*/
public static void get_Reflection_Method(ReflectionTest r) {
Class temp = r.getClass();
String className = temp.getName();
/*
* Note: 方法getDeclaredMethods()只能獲取到由當前類定義的全部方法,不能獲取從父類繼承的方法
* 方法getMethods() 不只能獲取到當前類定義的public方法,也能獲得從父類繼承和已經實現接口的public方法
* 請查閱開發文檔對這兩個方法的詳細描述。
*/
//Method[] methods = temp.getDeclaredMethods();
Method[] methods = temp.getMethods();
for (int i = 0; i < methods.length; i++) {
// 打印輸出方法的修飾域
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod) + " ");
// 輸出方法的返回類型
System.out.print(methods[i].getReturnType().getName());
// 獲取輸出的方法名
System.out.print(" " + methods[i].getName() + "(");
// 打印輸出方法的參數列表
Class[] parameterTypes = methods[i].getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.print(parameterTypes[j].getName());
if (parameterTypes.length > j+1) {
System.out.print(", ");
}
}
System.out.println(")");
}
}
在獲取類的成員方法時,有一個地方值得你們注意,就是getMethods()方法和getDeclaredMethods()方法。
getMethods():用於獲取類的全部的public修飾域的成員方法,包括從父類繼承的public方法和實現接口的public方法;
getDeclaredMethods():用於獲取在當前類中定義的全部的成員方法和實現的接口方法,不包括從父類繼承的方法。
你們能夠查考一下開發文檔的解釋:
getMethods() - Returns an array containing Method objects for all public methods for the class C represented by this Class.
Methods may be declared in C, the interfaces it implements or in the superclasses of C.
The elements in the returned array are in no particular order.
getDeclaredMethods() - Returns a Method object which represents the method matching the specified name and parameter types
that is declared by the class represented by this Class.
所以在示例代碼的方法get_Reflection_Method(...)中,ReflectionTest類繼承了Object類,實現了actionPerformed方法,並定義以下成員方法:
經過這兩個語句執行後的結果不一樣:
a、Method[] methods = temp.getDeclaredMethods()執行後結果以下:
b、Method[] methods = temp.getMethods()執行後,結果以下:
三、獲取類的成員變量(成員屬性)
存在四種獲取成員屬性的方法
Field getField(String name) 根據變量名,返回一個具體的具備public屬性的成員變量
Field[] getFields() 返回具備public屬性的成員變量的數組
Field getDeclaredField(String name) 根據變量名,返回一個成員變量(不分public和非public屬性)
Field[] getDelcaredField() 返回全部成員變量組成的數組(不分public和非public屬性)
get_Reflection_Field_Value()
/**
* 獲取反射類中的屬性和屬性值
* 輸出打印格式:"Modifier Type : Name = Value"
* Note: 對於未初始化的指針類型的屬性,將不輸出結果
*/
public static void get_Reflection_Field_Value(ReflectionTest r) {
Class temp = r.getClass(); // 獲取Class類的對象的方法之一
try {
System.out.println("public 屬性");
Field[] fb = temp.getFields();
for (int i = 0; i < fb.length; i++) {
Class cl = fb[i].getType(); // 屬性的類型
int md = fb[i].getModifiers(); // 屬性的修飾域
Field f = temp.getField(fb[i].getName()); // 屬性的值
f.setAccessible(true);
Object value = (Object)f.get(r);
// 判斷屬性是否被初始化
if (value == null) {
System.out.println(Modifier.toString(md) + " " + cl + " : " + fb[i].getName());
}
else {
System.out.println(Modifier.toString(md) + " " + cl + " : " + fb[i].getName() + " = " + value.toString());
}
}
System.out.println("public & 非public 屬性");
Field[] fa = temp.getDeclaredFields();
for (int i = 0; i < fa.length; i++) {
Class cl = fa[i].getType(); // 屬性的類型
int md = fa[i].getModifiers(); // 屬性的修飾域
Field f = temp.getDeclaredField(fa[i].getName()); // 屬性的值
f.setAccessible(true); // Very Important
Object value = (Object) f.get(r);
if (value == null) {
System.out.println(Modifier.toString(md) + " " + cl + " : " + fa[i].getName());
}
else {
System.out.println(Modifier.toString(md) + " " + cl + " : " + fa[i].getName() + " = " + value.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
四、獲取類、屬性、方法的修飾域
類Class、Method、Constructor、Field都有一個public方法int getModifiers()。該方法返回一個int類型的數,表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。
在開發文檔中,能夠查閱到,Modifier類中定義了若干特定的修飾域,每一個修飾域都是一個固定的int數值,列表以下:
該類不只提供了若干用於判斷是否擁有某中修飾域的方法boolean isXXXXX(int modifiers),還提供一個String toString(int modifier)方法,用於將一個表示修飾域組合值的int數轉換成描述修飾域的字符串。
5、如何調用類中的private方法
在介紹以前,先放一個代碼吧,這段代碼是參考其餘文章的代碼拷貝過來的,代碼不算長,可是動態調用類的成員方法的過程講解的通俗易懂。
LoadMethod.java
package crazypebble.reflectiontest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethod {
/**
* 在運行時加載指定的類,並調用指定的方法
* @param cName Java的類名
* @param MethodName 方法名
* @param types 方法的參數類型
* @param params 方法的參數值
* @return
*/
public Object Load(String cName, String MethodName, String[] types, String[] 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();
// 構建 方法的參數類型
Class paramTypes[] = this.getMethodTypesClass(types);
// 在指定類中獲取指定的方法
Method meth = cls.getMethod(MethodName, paramTypes);
// 構建 方法的參數值
Object argList[] = this.getMethodParamObject(types, params);
// 調用指定的方法並獲取返回值爲Object類型
retObject = meth.invoke(obj, argList);
} catch (Exception e) {
System.err.println(e);
}
return retObject;
}
/**
* 獲取參數類型,返回值保存在Class[]中
*/
public Class[] getMethodTypesClass(String[] types) {
Class[] cs = new Class[types.length];
for (int i = 0; i < cs.length; i++) {
if (types[i] != null || !types[i].trim().equals("")) {
if (types[i].equals("int") || types[i].equals("Integer")) {
cs[i] = Integer.TYPE;
}
else if (types[i].equals("float") || types[i].equals("Float")) {
cs[i] = Float.TYPE;
}
else if (types[i].equals("double") || types[i].equals("Double")) {
cs[i] = Double.TYPE;
}
else if (types[i].equals("boolean") || types[i].equals("Boolean")) {
cs[i] = Boolean.TYPE;
}
else {
cs[i] = String.class;
}
}
}
return cs;
}
/**
* 獲取參數Object[]
*/
public Object[] getMethodParamObject(String[] types, String[] params) {
Object[] retObjects = new Object[params.length];
for (int i = 0; i < retObjects.length; i++) {
if(!params[i].trim().equals("")||params[i]!=null){
if(types[i].equals("int")||types[i].equals("Integer")){
retObjects[i]= new Integer(params[i]);
}
else if(types[i].equals("float")||types[i].equals("Float")){
retObjects[i]= new Float(params[i]);
}
else if(types[i].equals("double")||types[i].equals("Double")){
retObjects[i]= new Double(params[i]);
}
else if(types[i].equals("boolean")||types[i].equals("Boolean")){
retObjects[i]=new Boolean(params[i]);
}
else{
retObjects[i] = params[i];
}
}
}
return retObjects;
}
}
要調用一個類的方法,首先須要一個該類的實例(固然,若是該類是static,就不須要實例了,至於緣由,你懂得!)。
一、建立一個類的實例
在獲得一個類的Class對象以後,咱們能夠利用類Constructor去實例化該對象。Constructor支持泛型,也就是它自己應該是Constructor<T>。這個類有一個public成員函數:T newInstance(Object... args),其中args爲對應的參數,咱們經過Constructor的這個方法來建立類的對象實例。
在代碼LoadMethod.java和LoadMethodEx.java中,分別給出了兩種實例化Class類的方法:一種是利用Constructor類調用newInstance()方法;另外一種就是利用Class類自己的newInstance()方法建立一個實例。兩種方法實現的效果是同樣的。
// 利用newInstance()方法,獲取構造方法的實例
// Class的newInstance方法,僅提供默認無參的實例化方法,相似於無參的構造方法
// Constructor的newInstance方法,提供了帶參數的實例化方法,相似於含參的構造方法
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
Object obj = cls.newInstance();
二、行爲
Method類中包含着類的成員方法的信息。在Method類中有一個public成員函數:Object invoke(Object receiver, Object... args),參數receiver指明瞭調用對象,參數args指明瞭該方法所須要接收的參數。因爲咱們是在運行時動態的調用類的方法,沒法提早知道該類的參數類型和返回值類型,因此傳入的參數的類型是Object,返回的類型也是Object。(由於Object類是全部其餘類的父類)
若是某一個方法是Java類的靜態方法,那麼Object receiver參數能夠傳入null,由於靜態方法從不屬於對象。
三、屬性
對類的成員變量進行讀寫,在Field類中有兩個public方法:
Object get(Object object),該方法可用於獲取某成員變量的值
Void set(Object object, Object value),該方法設置某成員變量的值
其中,Object參數是須要傳入的對象;若是成員變量是靜態屬性,在object可傳入null。
6、對LoadMethod.java的優化處理
在上一節中給出的LoadMethod.java中,類LoadMethod對固定參數類型的方法進行了調用,而且參數類型是經過一個String[]數組傳入,而後通過方法 getMethodTypesClass() 解析以後,才獲得了參數的具體的類型。同時在getMethodTypesClass()和getMethodParamObject()方法中,經過對傳入的字符串參數進行過濾後,再處理那些能夠匹配中的參數類型,其餘不能匹配的參數都作爲String對象來處理。若是咱們調用的方法所須要的參數不是簡單類型的變量,而是自定義的類對象,或者List列表,再若是咱們只知道類名和方法名,不知道方法的參數類型,那咱們該如何處理這些狀況呢?
所以,我對LoadMethod類進行了必定的優化處理。先附上代碼:
LoadMethodEx.java
package crazypebble.reflectiontest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethodEx {
/**
* 在運行時加載指定的類,並調用指定的方法
* @param cName Java的類名
* @param MethodName 方法名
* @param params 方法的參數值
* @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();
// 根據方法名獲取指定方法的參數類型列表
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;
}
/**
* 獲取參數類型,返回值保存在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)) { // 不是咱們須要的參數,則進入下一次循環
continue;
}
cs = mtd[i].getParameterTypes();
}
return cs;
}
}
咱們經過前面幾節的一系列分析,只要咱們知道了一個類的類名(包括其包的路徑),那咱們就能夠經過Class類的一系列方法,獲得該類的成員變量、構造方法、成員方法、以及成員方法的參數類型和返回類型、還有修飾域等信息。
若是咱們已經知道某個類名和須要動態調用的方法名,怎樣才能不用傳入方法的參數類型就能夠調用該方法呢?
在已知類名的狀況下,咱們能夠打印輸出該類的全部信息,固然包括類的成員方法;而後經過給定的方法名,對打印輸出的方法名進行篩選,找到咱們須要的方法;再經過該方法的Method對象,獲得該方法的參數類型、參數數量、和返回類型。那麼咱們在外部動態調用該方法時,就不須要關心該類須要傳入的參數類型了,只須要傳入類名、方法名、參數值的信息便可。筆者實現了一個類LoadMethodEx,先從兩個類的同一個方法須要的參數方面作一個對比:
一、LoadMethodEx類,少了一個參數(方法參數類型列表),本文直接從類LoadMethod內部獲取該參數類型列表,不須要用戶傳入該信息,好處其實也不言而喻了。
二、方法的參數值:類LoadMethod是將全部的方法參數都作爲一個String來傳入,在傳入再進行解析;而本文則直接使用Object類型作爲參數類型,由於invoke(Object obj, Object...args)方法自己所須要的參數類型就是Object,避免了沒必要要的參數類型變換。
在調用LoadMethod的Load()方法時,用戶只須要知道類名、方法名,而且將已經初始化的參數先向上轉型爲Object,而後傳遞給Load()方法便可。方法的返回值爲Object,這個確定是由用戶根據本身的須要,再轉換成本身所需的類型。
執行結果
屬性:
public 屬性
public class java.lang.Integer : bInteger = 4
public class java.lang.String : strB = crazypebble
public & 非public 屬性
private int : bInt = 0
public class java.lang.Integer : bInteger = 4
public class java.lang.String : strB = crazypebble
private class java.lang.String : strA
構造方法:
public crazypebble.reflectiontest.ReflectionTest()
protected crazypebble.reflectiontest.ReflectionTest(int, java.lang.String)
父類/接口:
父類: java.lang.Object
接口0: java.awt.event.ActionListener
接口1: java.io.Serializable
成員方法:
public int abc(int, java.lang.String)
public void actionPerformed(java.awt.event.ActionEvent)
public final native void wait(long)
public final void wait()
public final void wait(long, int)
public boolean equals(java.lang.Object)
public java.lang.String toString()
public native int hashCode()
public final native java.lang.Class getClass()
public final native void notify()
public final native void notifyAll()
反射機制調用方法:LoadMethod
crazypebble ---> 1-hello, android-1!
反射機制調用方法:LoadMethodEx
crazypebble ---> 2-hello, android-2?
返回結果:0
7、總結
關於反射機制,其實還有一個比較敏感的話題,就是反射機制帶來咱們的安全性問題。因爲我在這方面研究的不是很深刻,因此講很差。你們有空能夠跟蹤一下在本文最後提供的兩個連接,裏面有一些介紹。
咱們介紹了Java的反射機制,可是在Android平臺下,反射機制具體有沒有什麼用途呢?答案是確定的。推薦你們看一篇文章《利用Java反射技術阻止經過按鈕關閉對話框》,這篇文章爲CSDN推薦爲精品文章,因此仍是很值得一看的。我特意從CSDN轉載過來供你們一塊兒學習。
原連接:http://blog.csdn.net/nokiaguy/archive/2010/07/27/5770263.aspx
轉載連接:http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014297.html
程序實現的源碼:
AndroidReflection
package crazypebble.androidreflection;
import java.lang.reflect.Field;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
private static Button btnHandler = null;
private static Button btnShowing = null;
AlertDialog alertDialog = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnHandler = (Button)findViewById(R.id.btn_mHandler);
btnHandler.setOnClickListener(new ButtonListener());
btnShowing = (Button)findViewById(R.id.btn_mShowing);
btnShowing.setOnClickListener(new ButtonListener());
alertDialog = new AlertDialog.Builder(this)
.setTitle("abc")
.setMessage("Content")
.setIcon(R.drawable.icon)
.setPositiveButton("肯定", new PositiveClickListener())
.setNegativeButton("取消", new NegativeClickListener())
.create();
}
private class ButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_mHandler:
modify_mHandler();
alertDialog.show();
break;
case R.id.btn_mShowing:
alertDialog.show();
break;
default:
break;
}
}
}
private class PositiveClickListener implements android.content.DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
// 方法二時啓用
modify_dismissDialog(false);
}
}
private class NegativeClickListener implements android.content.DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
// 方法一時啓用
//dialog.dismiss();
// 方法二時啓用
modify_dismissDialog(true);
}
}
/*
* 第一種方法:修改AlertController類的private成員變量mHandler的值
*/
public void modify_mHandler() {
try {
Field field = alertDialog.getClass().getDeclaredField("mAlert");
field.setAccessible(true);
// 獲取mAlert變量的值
Object obj = field.get(alertDialog);
field = obj.getClass().getDeclaredField("mHandler");
field.setAccessible(true);
// 修改mHandler變量的值,使用新的ButtonHandler類
field.set(obj, new MyButtonHandler(alertDialog));
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 第二種方法:修改dismissDialog()方法
*/
public void modify_dismissDialog(boolean flag) {
try {
Field field = alertDialog.getClass().getSuperclass().getDeclaredField("mShowing");
field.setAccessible(true);
// 將mShowing變量設爲false,表示對話框已經關閉
field.set(alertDialog, flag);
alertDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyButtonHandler.java
package crazypebble.androidreflection;
import java.lang.ref.WeakReference;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
public class MyButtonHandler extends Handler{
// Button clicks have Message.what as the BUTTON{1,2,3} constant
private static final int MSG_DISMISS_DIALOG = 1;
private WeakReference<DialogInterface> mDialog;
public MyButtonHandler(DialogInterface dialog) {
mDialog = new WeakReference<DialogInterface>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
break;
}
}
}
看完上面這篇文章以後,但願你們明確一點的是:反射機制經過void setAccessible(boolean flag)方法能夠獲得一個類的private的方法和屬性,使用這些private的方法和屬性,已經能夠作一些超越限制的事情了。因此在使用過程,還需謹慎啊!
代碼中對每一步都有詳細的解釋,可是因爲註釋部分太多,可能對閱讀有必定的障礙,還請你們諒解。同時本文主要參考了一下兩篇文章:
一、 http://zlb1986.iteye.com/blog/937781
二、 http://www.cnblogs.com/keis/archive/2011/03/29/1998736.html
在此感謝兩位的文章爲本文提供了必定的基礎,爲我學習Java的反射機制提供了很好的教程。本文也是一篇學習總結,若是本文對這兩篇文章的做者有冒犯之處,請及時與本人聯繫。若是各位同窗發現本文和代碼的錯誤之處的話,還請指正,一塊兒學習交流。
附:兩個工程的下載地址,供你們一塊兒學習研究。http://u.115.com/file/f68453a0ca