Posted on 2012-06-12 16:26
陜西BOY 閱讀(221)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
java基礎(chǔ)知識(shí)點(diǎn)
Class反射對(duì)象描述類(lèi)語(yǔ)義結(jié)構(gòu),可以從Class對(duì)象中獲取構(gòu)造函數(shù)、成員變量、方法類(lèi)等類(lèi)元素的反射對(duì)象,并以編程的方式通過(guò)這些反射對(duì)象對(duì)目標(biāo)類(lèi)對(duì)象進(jìn)行操作。這些反射對(duì)象類(lèi)在java.reflect包中定義,下面是最主要的三個(gè)反射類(lèi):
- ? Constructor:類(lèi)的構(gòu)造函數(shù)反射類(lèi),通過(guò)Class#getConstructors()方法可以獲得類(lèi)的所有構(gòu)造函數(shù)反射對(duì)象數(shù)組。在JDK5.0中,還可以通過(guò)getConstructor(Class... parameterTypes)獲取擁有特定入?yún)⒌臉?gòu)造函數(shù)反射對(duì)象。Constructor的一個(gè)主要方法是newInstance(Object[] initargs),通過(guò)該方法可以創(chuàng)建一個(gè)對(duì)象類(lèi)的實(shí)例,相當(dāng)于new關(guān)鍵字。在JDK5.0中該方法演化為更為靈活的形式:newInstance (Object... initargs)。
- ? Method:類(lèi)方法的反射類(lèi),通過(guò)Class#getDeclaredMethods()方法可以獲取類(lèi)的所有方法反射類(lèi)對(duì)象數(shù)組Method[]。在JDK5.0中可以通過(guò)getDeclaredMethod(String name, Class... parameterTypes)獲取特定簽名的方法,name為方法名;Class...為方法入?yún)㈩?lèi)型列表。Method最主要的方法是invoke(Object obj, Object[] args),obj表示操作的目標(biāo)對(duì)象;args為方法入?yún)ⅲa清單3 10③處演示了這個(gè)反射類(lèi)的使用方法。在JDK 5.0中,該方法的形式調(diào)整為invoke(Object obj, Object... args)。此外,Method還有很多用于獲取類(lèi)方法更多信息的方法: 1)Class getReturnType():獲取方法的返回值類(lèi)型;
2)Class[] getParameterTypes():獲取方法的入?yún)㈩?lèi)型數(shù)組;
3)Class[] getExceptionTypes():獲取方法的異常類(lèi)型數(shù)組;
4)Annotation[][] getParameterAnnotations():獲取方法的注解信息,JDK 5.0中的新方法; - ? Field:類(lèi)的成員變量的反射類(lèi),通過(guò)Class#getDeclaredFields()方法可以獲取類(lèi)的成員變量反射對(duì)象數(shù)組,通過(guò)Class#getDeclaredField(String name)則可獲取某個(gè)特定名稱(chēng)的成員變量反射對(duì)象。Field類(lèi)最主要的方法是set(Object obj, Object value),obj表示操作的目標(biāo)對(duì)象,通過(guò)value為目標(biāo)對(duì)象的成員變量設(shè)置值。如果成員變量為基礎(chǔ)類(lèi)型,用戶可以使用Field類(lèi)中提供的帶類(lèi)型名的值設(shè)置方法,如setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。
此外,Java還為包提供了Package反射類(lèi),在JDK 5.0中還為注解提供了AnnotatedElement反射類(lèi)。總之,Java的反射體系保證了可以通過(guò)程序化的方式訪問(wèn)目標(biāo)類(lèi)中所有的元素,對(duì)于private或protected的成員變量和方法,只要JVM的安全機(jī)制允許,也可以通過(guò)反射進(jìn)行調(diào)用,請(qǐng)看下面的例子:
代碼清單3-12 PrivateCarReflect
package com.baobaotao.reflect;
public class PrivateCar {
//①private成員變量:使用傳統(tǒng)的類(lèi)實(shí)例調(diào)用方式,只能在本類(lèi)中訪問(wèn)
private String color;
//②protected方法:使用傳統(tǒng)的類(lèi)實(shí)例調(diào)用方式,只能在子類(lèi)和本包中訪問(wèn)
protected void drive(){
System.out.println("drive private car! the color is:"+color);
}
}
color變量和drive()方法都是私有的,通過(guò)類(lèi)實(shí)例變量無(wú)法在外部訪問(wèn)私有變量、調(diào)用私有方法的,但通過(guò)反射機(jī)制卻可以繞過(guò)這個(gè)限制:
public class PrivateCarReflect {
public static void main(String[] args) throws Throwable{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.baobaotao.reflect.PrivateCar");
PrivateCar pcar = (PrivateCar)clazz.newInstance();
Field colorFld = clazz.getDeclaredField("color");
//①取消Java語(yǔ)言訪問(wèn)檢查以訪問(wèn)private變量
colorFld.setAccessible(true);
colorFld.set(pcar,"紅色");
Method driveMtd = clazz.getDeclaredMethod("drive",(Class[])null);
//Method driveMtd = clazz.getDeclaredMethod("drive"); JDK5.0下使用
//②取消Java語(yǔ)言訪問(wèn)檢查以訪問(wèn)protected方法
driveMtd.setAccessible(true);
driveMtd.invoke(pcar,(Object[])null);
}
}
運(yùn)行該類(lèi),打印出以下信息:
引用
drive private car! the color is:紅色
在訪問(wèn)private、protected成員變量和方法時(shí)必須通過(guò)setAccessible(boolean access)方法取消Java語(yǔ)言檢查,否則將拋出IllegalAccessException。如果JVM的安全管理器設(shè)置了相應(yīng)的安全機(jī)制,調(diào)用該方法將拋出SecurityException。