Object result = method.invoke(bean);
反射(Reflection)是Java 程序開發(fā)語言的特征之一,它允許運(yùn)行中的 Java 程序獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性。
程序中對象的類型都是在編譯期就確定下來的,而Java反射機(jī)制可以動態(tài)地創(chuàng)建對象并調(diào)用其屬性。但在有的時(shí)候并沒有進(jìn)行編譯期就要直接使用,比如class.forName方法。
反射的核心是JVM在運(yùn)行時(shí)才動態(tài)加載類或調(diào)用方法/訪問屬性,它不需要事先(寫代碼的時(shí)候或編譯期)知道對象的類型。
Java反射框架主要提供以下功能:
1.在運(yùn)行時(shí)動態(tài)進(jìn)行類加載;
2.在運(yùn)行時(shí)創(chuàng)建一個(gè)對象;
3.在運(yùn)行時(shí)獲取類(對象)的任意成員變量和方法
4.在運(yùn)行時(shí)調(diào)用任意一個(gè)對象的方法(通過反射甚至可以調(diào)用private方法);
重點(diǎn)是運(yùn)行時(shí)而不是編譯時(shí)
當(dāng)我們在使用IDE(如Eclipse,IDEA)時(shí),當(dāng)我們輸入一個(gè)對象或類并想調(diào)用它的屬性或方法時(shí),一按點(diǎn)號,編譯器就會自動列出它的屬性或方法,這里就會用到反射。
反射最重要的用途就是開發(fā)各種通用框架。
很多框架(比如Spring)都是配置化的(比如通過XML文件配置JavaBean,Action之類的),為了保證框架的通用性,它們可能需要根據(jù)配置文件加載不同的對象或類,調(diào)用不同的方法,這個(gè)時(shí)候就必須用到反射——運(yùn)行時(shí)動態(tài)加載需要加載的對象。
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">
<result>index.jsp</result>
<result name="error">login.jsp</result>
</action>
配置文件與Action建立了一種映射關(guān)系,當(dāng)View層發(fā)出請求時(shí),請求會被StrutsPrepareAndExecuteFilter攔截,然后StrutsPrepareAndExecuteFilter會去動態(tài)地創(chuàng)建Action實(shí)例。
struts與spring mvc的區(qū)別是struts是原型的,springmvc是單列的。
獲得Class對象的三種方法:
(1)使用Class類的forName靜態(tài)方法
(2)直接獲取某一個(gè)對象的class,比如 a.class
(3)調(diào)用某個(gè)對象的getClass()方法,比如 a.getClass()
instanceof 和 isInstance區(qū)別:
obj instanceof Type
class.isInstance(obj)
System.out.println("ok" instanceof String);
System.out.println("ok".getClass().isInstance(""));
通過反射來生成對象主要有兩種方式:
(1)使用Class對象的newInstance()方法來創(chuàng)建Class對象對應(yīng)類的實(shí)例
(2)先通過Class對象獲取指定的Constructor對象,再調(diào)用Constructor對象的newInstance()方法來創(chuàng)建實(shí)例。這種方法可以用指定的構(gòu)造器構(gòu)造類的實(shí)例:
//獲取String所對應(yīng)的Class對象
Class<?> c = String.class;
//獲取String類帶一個(gè)String參數(shù)的構(gòu)造器
Constructor constructor = c.getConstructor(String.class);
//根據(jù)構(gòu)造器創(chuàng)建實(shí)例
Object obj = constructor.newInstance("23333");
System.out.println(obj);
獲取某個(gè)Class對象的方法集合,主要有以下幾個(gè)方法:
getDeclaredMethods()方法返回類或接口聲明的所有方法,包括公共、保護(hù)、默認(rèn)(包)訪問和私有方法,但不包括繼承的方法。
public Method[] getDeclaredMethods() throws SecurityException
getMethods()方法返回某個(gè)類的所有公用(public)方法,包括其繼承類的公用方法。
public Method[] getMethods() throws SecurityException
getMethod方法返回一個(gè)特定的方法,其中第一個(gè)參數(shù)為方法名稱,后面的參數(shù)為方法的參數(shù)對應(yīng)Class的對象
public Method getMethod(String name, Class<?>... parameterTypes)
獲取類的成員變量(字段)信息,直接使用較少,因?yàn)樽兞恳话銥樗接械摹?/p>
getFiled: 訪問公有的成員變量
getDeclaredField:所有已聲明的成員變量。但不能得到其父類的成員變量
getFileds和getDeclaredFields用法同上(參照Method)
當(dāng)我們從類中獲取了一個(gè)方法后,我們就可以用invoke()方法來調(diào)用這個(gè)方法。invoke方法的原型為:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
反射調(diào)用方法時(shí)可以忽略權(quán)限檢查,因此可能會破壞封裝性而導(dǎo)致安全問題。