最近溫習(xí)了一下java的反射機(jī)制,發(fā)現(xiàn)之前學(xué)習(xí)反射的時(shí)候沒(méi)有留下只言片語(yǔ),補(bǔ)上補(bǔ)上?。?!
反射的概念:
比如我們想看看我們自己長(zhǎng)什么樣子,我們自己肯定看不到自己長(zhǎng)什么樣子,所以,我們借助鏡子,通過(guò)鏡子的反射看到我們的樣子,可以看清我們自己的五官;
同理,在Java中運(yùn)行的類,也有這么一面鏡子,可以反射該類的一些行為和屬性,而這個(gè)反射就體現(xiàn)在java.lang.Class中;
通過(guò)Class對(duì)象,可以得到某個(gè)類的一些行為和屬性,甚至我們通過(guò)反射可以操作這個(gè)對(duì)象的行為和屬性;這就是反射機(jī)制;
要想理解反射,我們先來(lái)了解一下java.lang.Class這個(gè)‘萬(wàn)能’的類;
獲取Class實(shí)例的幾種方式:
(1)通過(guò)全類名獲取Class實(shí)例,這也是最常用的一種方式
public void testClassForName(){
? ??String className = "com.test.bean.Preson";
? ??Class clazz = Class.forName(className);
}
為什么說(shuō)這是一種最常用的一種方式,相信大家都用過(guò)Spring或者M(jìn)yBatis等等這類框架,在使用這類框架的時(shí)候,免不了與該框架的XML配置文件打交道,在很多配置的地方都會(huì)填寫(xiě)一個(gè)全類名;
看過(guò)源碼的同學(xué)應(yīng)該就知道,因?yàn)檫@些框架會(huì)先解析XML配置文件的到這個(gè)全類名,通過(guò)這個(gè)全類名來(lái)得到Class對(duì)象,完成后面的反射調(diào)用的動(dòng)作;
(2)通過(guò)getClass的方式得到Class實(shí)例
public void testGetClass(Object obj){
? ??Class clazz = obj.getClass();
}
這里為什么用Object作為入?yún)⒛??因?yàn)楦鄷r(shí)候我們不知道外面?zhèn)鬟M(jìn)來(lái)的是什么對(duì)象,使用Object接受就可以接受任何java對(duì)象,那么通過(guò)反射就可以獲得到相應(yīng)的Class
(3)通過(guò)類.class的形式獲取
public void testClass(){
? ??Class clazz = Person.class;
}
(4)通過(guò)類加載器的形式獲取
public void testClassLoader(){
? ? ClassLoader classLoader = this.getClass().getClassLoader();
? ? Class clazz = classLoader.loadClass(className);
}
也就是說(shuō),我們得到Class對(duì)象,就可以為所欲為了,可以利用反射機(jī)制來(lái)調(diào)用該類的方法或者屬性;
說(shuō)完Class,我們說(shuō)下幾個(gè)常用的相關(guān)類;這幾個(gè)類的使用方式都差不多;
java.lang.reflect.Constructor
這個(gè)類是專門描述某個(gè)類的構(gòu)造方法,可以通過(guò)Class對(duì)象獲得到類中定義的構(gòu)造方法;
//獲取構(gòu)造器
public void testConstructor() throws Exception{
????String className = "com.test.bean.Person";
????Class clazz = Class.forName(className);
????//通過(guò)Class對(duì)象獲取Constructor對(duì)象
????Constructor constructor = clazz.getConstructor();
????System.out.println(constructor.getName());
}
parameterTypes:表示構(gòu)造器的參數(shù)列表,如果想獲取無(wú)參構(gòu)造器,這個(gè)參數(shù)不要傳了;
但是這個(gè)clazz.getConstructor();只能獲取到構(gòu)造器為public類型的,不能獲取到private修飾的構(gòu)造器;
//獲取私有構(gòu)造器
public void testConstructor() throws Exception{
????String className = "com.test.bean.Person";
????Class clazz = Class.forName(className);
????//通過(guò)Class對(duì)象獲取private 修飾的Constructor對(duì)象
????Constructor constructor = clazz.getDeclaredConstructor();
????System.out.println(constructor.getName());
}
同時(shí),如果想調(diào)用私有的構(gòu)造器,調(diào)用前要調(diào)用一下setAccessible(true),獲取調(diào)用私有方法的權(quán)限,否則會(huì)報(bào)異常
//獲取私有構(gòu)造器,并執(zhí)行私有構(gòu)造器
public void testConstructor() throws Exception{
????String className = "com.test.bean.Person";
????Class clazz = Class.forName(className);
????//通過(guò)Class對(duì)象獲取private 修飾的Constructor對(duì)象
????Constructor constructor = clazz.getDeclaredConstructor();
????constructor.setAccessible(true);
????//調(diào)用構(gòu)造器創(chuàng)建實(shí)例
????Object obj = constructor.newInstance();
????System.out.println(constructor.getName());
}
通過(guò)上面,就會(huì)發(fā)現(xiàn),Java的三大特性:封裝、繼承、多態(tài),這里面的封裝對(duì)反射來(lái)說(shuō)是無(wú)用了,通過(guò)反射可以破壞他的封裝;啊哈哈哈。。。
java.lang.reflect.Method
這個(gè)類描述了類中的方法,通過(guò)這個(gè)Method對(duì)象,可以操作類中定義的方法;
//通過(guò)反射獲得類定義的Mehtod,但是獲取不到private修飾的方法
Mehtod method = clazz.getMethod('setName', String.class);
//獲取本類中定義的方法,包括私有方法也可以獲取
Method method = clazz.getDeclaredMethod("test",String.class);
獲取指定的Method的時(shí)候需要傳入兩個(gè)參數(shù):
1.方法名
2.方法的參數(shù)列表類型,比如方法的入?yún)⑹荢tring類型的,那么這里就是String.class
//獲取本類和父類中public的所有方法集合,但是獲取不到私有方法
Method[] methods = clazz.getMethods();
//獲取本類所有方法集合,包括私有方法
Method[] methods = clazz.getDeclaredMethods();
同樣,在調(diào)用private修飾的方法之前,要調(diào)用setAccessible(true);
//通過(guò)method調(diào)用方法,這個(gè)才是重點(diǎn)
public Object invoke(Object obj,Object... args);
obj:調(diào)用哪個(gè)對(duì)象中的方法
args:方法的參數(shù)
method.invoke(clazz.newInstance(), "helloWorld");
java.lang.reflect.Field:屬性
public void testField() throws Exception{
????String className = "com.test.classloader.bean.Person";
????Class clazz = Class.forName(className);
????//先通過(guò)反射獲得到實(shí)例
????Object obj = clazz.newInstance();
????//獲取對(duì)象中指定的屬性
????Field field = clazz.getField("name");
????//為屬性賦值
????field.set(obj, "hello");
????System.out.println(obj);
? ??//獲取private 修飾的成員屬性
????Field field1 = clazz.getDeclaredField("name");
????field1.setAccessible(true);
????field1.set(obj, "world");
????System.out.println(obj);
}