Java中的反射機制
反射是Java程序開發語言的特徵之一。它允許動態地發現和綁定類、方法、字段,以及所有其他的由語言所產生的元素。反射可以做的不僅僅是簡單地列舉類、字段以及方法。通過反射,還能夠在需要時完成創建實例、調用方法以及訪問字段的工作。反射是Java被視爲動態(或準動態)語言的關鍵。
歸納起來,Java反射機制主要提供了一下功能:
在運行時判斷任意一個對象所屬的類。
在運行時構造任意一個類的對象。
在運行時判斷任意一個類所具有的成員變量和方法。
在運行時調用任意一個對象的方法。通過反射甚至可以調用到private的方法。
生成動態代理。
Java反射API
Java反射所需的類並不多,主要有java.lang.Class類和java.lang.reflect包中的Field、Constructor、Method、Array類,下面對這些類做一個簡單的說明。
Class類:Class
類的實例表示正在運行的
Java 應用程序中的類和接口。
Field類:Field
提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。 簡單的理解可以把它看成一個封裝反射類的屬性的類。
Constructor類:Constructor
提供關於類的單個構造方法的信息以及對它的訪問權限。Constructor類封裝了反射類的構造方法。
Method類:Method
提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。它是用來封裝反射類方法的一個類。
其中,Class類是Java反射的起源,針對任何一個你想探勘的類,只有先爲它產生一個Class類的對象,接下來才能通過Class對象獲取其他想要的信息。
Java程序在運行時,系統會對所有的對象進行所謂的運行時類型標識,用來保存這些類型信息的類就是Class類。Class類封裝一個對象和接口運行時的狀態。
JVM爲每種類型管理着一個對一無二的Class對象。也就是說,每個類(型)都有一個Class對象。Java程序運行過程中,當需要創建某個類的實例時,JVM首先檢查所要加載的類對應的Class對象是否存在。如果還不存在,JVM就會根據類名查找對應的字節碼文件並加載,接着創建對應的Class對象,最後才創建出這個類的實例。
也就是說,運行中的類或者接口在JVM中都會有一個對應的Class對象存在,它保存了對應類和接口的類型信息。要想獲取類和接口的相應信息,需要先獲取這個Class對象。
一.獲取字節碼文件對象(Class對象)。
三種方式:
1,getClass()方法。調用Object類的getClass()方法來得到Class對象。
特點:必須要明確具體的類,而且要通過該類創建對象。用對象的方法纔可以獲取。public final Class<?>getClass(); 此方法爲Object類中方法。
public class ReflectDemo1{
public staticvoid getClassObject_1(){
Personp = new Person(); //1,創建Person對象
Classclazz = p.getClass(); //2,獲取字節碼對象。getClass();
Personp2 = new Person();
Classclazz2 = p2.getClass();
System.out.println(clazz==clazz2); //返回true
}
}
2,通過類型的class靜態屬性獲取其對應的Class對象
每一個數據類型都有一個靜態的屬性class,每一個類型都對應自己的Class類型的對象。
特點:雖然不用在創建對象了,但是還是要先明確該類,在調用其靜態的屬性完成。
public class ReflectDemo2{
publicstaticvoid getClassObject_2() {
Class clazz = Person.class;
//Class clazz = int.class;
}
}
3,使用的是Class類中的forName方法。根據指定的類名來獲取其字節碼文件對象。
特點:只需要一個類名字符串即可。forName方法自動會根據指定的字符串名稱去查找對應的類文件。如果找到就將其加載進內存,並封裝成Class對象。
如果沒有找到拋出ClassNotFoundException
* 因爲只需要字符串名稱所以擴展性很強。
* 以這種方式爲主提高程序的擴展性
public class ReflectDemo2{
publicstaticvoid getClassObject_3() throws Exception {
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
System.out.println(clazz);
}
}
二.通過字節碼文件創建對象
1.使用類中空參構造函數進行初始化對象。
通過字節碼文件對象的newInstance方法完成該類實例的創建。
Class clazz =Class.forName("cn.itcast.bean.Person");
Object obj = clazz.newInstance();//該方法使用的就是該類中的空參數構造函數進行初始化對象。
2. 通過有參數的構造函數進行實例化
既然要根據指定的構造函數進行初始化,就必須要先獲取要用於初始化的構造函數,再通過該構造函數進行對象創建的初始化。
publicstaticvoid createObject_2() throws Exception{
Classclazz = Class.forName("cn.itcast.bean.Person");
Constructorconstructor = clazz.getConstructor(String.class,int.class); //獲取指定參數的構造函數。當然是Class對象完成。
Objectobj = constructor.newInstance("zhangsan",28); //通過該構造函數進行對象的創建並初始化。並傳遞指定的實際參數。
}
三.通過反射獲取類中字段
publicstaticvoidgetFieldDemo() throwsException{
StringclassName = "cn.itcast.bean.Person";
Classclazz = Class.forName(className);
Objectobj = clazz.newInstance();
//獲取該類中的名稱爲age(Private修飾)的字段。
//Field field = clazz.getField("age");//該方法只能獲取公有的字段。
//獲取私有字段必須使用getDeclaredField();
Fieldfield = clazz.getDeclaredField("age");
//調用取消對成員的訪問控制檢查的能力的方法。
field.setAccessible(true);//暴力訪問。
//System.out.println(field);
field.set(obj,38);
Objectvalue = field.get(obj);//因爲age私有,會出現IllegalAccessException:
System.out.println("value="+value);
}
四.通過反射獲取類中方法
Class類中的方法:
public Method getMethod(Stringname,
Class<?>...parameterTypes):返回一個Method
對象,它反映此Class
對象所表示的類或接口的指定公共成員方法。name
參數是一個String
,用於指定所需方法的簡稱。parameterTypes
參數是按聲明順序標識該方法形參類型的Class
對象的一個數組。如果parameterTypes
爲null
,則按空數組處理。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes): 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。
Method類中的方法:
public Object invoke(Object obj, Object... args):對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。
publicstaticvoid getSingleMethodDemo() throws Exception {
StringclassName = "cn.itcast.bean.Person";
Classclazz = Class.forName(className);
Objectobj = clazz.newInstance();
//獲取一個空參數的公有權限方法。pubMethod
Method method =clazz.getMethod("pubMethod", null);
//方法怎麼運行,方法對象自己最清楚。
method.invoke(obj, null);
//獲取有參數的public方法。parMethod.
Method method = clazz.getMethod("parMethod",String.class,int.class);
method.invoke(obj,"xiaoming",47);
//獲取私有方法。
Method method =clazz.getDeclaredMethod("priMethod", null);
method.setAccessible(true);
method.invoke(obj, null);
//獲取靜態的方法。
Methodmethod = clazz.getMethod("staMethod", null);
method.invoke(null, null); //靜態方法不需要創建對象來調用。後一個null爲空參
}
/*
* 獲取所有方法。
*/
publicstaticvoidgetMethodDemo() throwsException {
StringclassName = "cn.itcast.bean.Person";
Classclazz = Class.forName(className);
Objectobj = clazz.newInstance();
//獲取所有方法。
Method[]methods = clazz.getMethods();
methods= clazz.getDeclaredMethods();
for(Method method : methods){
System.out.println(method);
}
}
---------------------- android培訓、java培訓、期待與您交流! ----------------------詳細請查看:http://edu.csdn.net/heima