詳解Java反射機制(Reflection)
反射機制的作用
JAVA反射機制是在運行狀態(tài)中,對于任意一個類黔牵,都能夠知道這個類的所有屬性和方法留攒;對于任意一個對象煤惩,都能夠調用它的任意方法和屬性,實現(xiàn)了基本的動態(tài)性炼邀。
詳解反射機制
類的組成
正如我們所知道的魄揉,一個類的組成包括了一下幾個部分:類名、構造器拭宁、方法洛退、域、注解杰标,所以為了能夠獲得任意一個類的對象兵怯,則需要能夠獲得該類的全部組成,JDK中的Reflection包為我們提供了一下幾個對應類的各個組成部分的類腔剂,分別是Class
媒区, Construtor
,Method
掸犬, Field
袜漩,下面我們詳細地了解各個 "組成類"。
-
Class
- Class類是一個比較特殊的類湾碎,之所以說它特殊宙攻,是因為在每個Java對象在加載到JVM中之后,都會產(chǎn)生一個Class的對象介褥,用來跟蹤該對象所代表的類粘优。下面我們做一個小實驗
public void test(){ String str1 = "I love Java"; String str2 = new String("I Lov Java"); System.out.println(str1.getClass()); System.out.println(str2.getClass()); System.out.println(String.class); }
輸出的結果分別如下:
class java.lang.String class java.lang.String class java.lang.String
上面的結果說明了,String的任意不同對象在JVM中只有一個Class對象呻顽,也就是說Class對象在JVM中只有唯一一份。
- 獲得Class對象的實例
在實際的應用中丹墨,有三種方式可以獲得Class對象廊遍,如下代碼所示:(這里為了下文的方便,我創(chuàng)建了一個Person類贩挣,具有name喉前,age兩個屬性域,以及生成對應的set王财,get方法)
String className = "cn.xuhuanfeng.reflection.Person"; Class<?> clazz1 = Class.forName(className); // 獲得Class對象 Class<Person> clazz2 = Person.class; // 獲得Class對象 Class<? extends Person> clazz3 = (new Person()).getClass(); // 獲得Class對象
創(chuàng)建實例
獲得了Class的對象之后卵迂,我們就可以利用它來創(chuàng)建類的實例,從而實現(xiàn)在運行時創(chuàng)建類绒净,如下代碼所示:
Person person = (Person)clazz2.newInstance();
這樣我們就獲得了一個Person對象见咒,不過這里要注意的是,Class的`newInstance()` 方法只能使用無參構造函數(shù)創(chuàng)建挂疆,也就是說改览,只有當該類具有無參構造方法時下翎,才能使用這種方法來獲得一個實例,這看上去比較無奈宝当,不過也不用太擔心视事,通過下面將介紹到的Construtor的`newInstance()` 方法即可以使用該類的有參夠構造方法來獲得實例。
- 獲得類名
有時候我們需要獲得類的類名庆揩,雖然不是總是需要俐东,我們可以通過下面的方法來獲得
System.out.println(clazz1.getName());//cn.xuhuanfeng.reflection.Person
System.out.println(clazz1.getSimpleName());//Person
相信大家可以看出上面兩者的區(qū)別,這里就不進行敘述订晌。
-
Construtor
正如Class表述一個類的總體情況一樣虏辫,Construtor描述的是一個類的構造器類,沒錯腾仅,構造器也是一種類乒裆。
Constructor[] construtor = clazz.getConstructors(); //獲得Public類型的構造器
Constructor[] construtor2 = clazz.getDeclaredConstructors(); // 獲得所有類型的構造器
construtor以及construtor2的內容輸出如下:
``` Java
// construtor
public cn.xuhuanfeng.reflection.Person()
public cn.xuhuanfeng.reflection.Person(java.lang.String,int)
// construtor2
public cn.xuhuanfeng.reflection.Person()
public cn.xuhuanfeng.reflection.Person(java.lang.String,int)
這里由于Person只有public類型的構造器,所以兩者包含的內容相同推励。
當然我們還可以通過制定參數(shù)類型來獲得特定的構造器
Constructor construtor3 = clazz.getConstructor(String.class,int.class);
上面我們提到了通過構造器來獲得帶參數(shù)類型的實例鹤耍,其實就是通過上面的方式獲得帶參數(shù)的構造器對象,然后調用器newInstance(parameter ...)
方法即可验辞,如下所示:
Person person1 = (Person)construtor3.newInstance("xuhanfeng",23);
這樣稿黄,我們就實現(xiàn)了通過任意構造器創(chuàng)建對象。
-
Method
Method 描述的是一個類的方法跌造,同上面的Construtor類似杆怕,這里我們不進行過多的解釋,直接看代碼演示壳贪。
Method[] methods = clazz.getMethods(); // 獲得所有的public方法
Method[] methods2 = clazz.getDeclaredMethods(); // 獲得所有的方法
Method method3 = clazz.getDeclaredMethod("setName", String.class);// 獲得指定的方法
看到這里陵珍,相信你會發(fā)現(xiàn),基本上跟前面的Construtor是類似违施,不過這里也有點不用互纯,就是調用方法的時候,使用的是invoke(obj,params)
方法磕蒲,如下
method3.invoke(person, "xuhuanfeng");// person 為前面獲得的實例
這樣留潦,我們就實現(xiàn)了調用任意方法了。
-
Field
Field是用來描述一個類所有的域的類辣往,相信經(jīng)過前面的Construtor以及Method兔院,對于Field我們已經(jīng)不用再進行過多解釋了,直接看代碼
Field[] fields = clazz.getFields(); // 獲得所有的public的域
Field[] fields2 = clazz.getDeclaredFields(); // 獲得所有的域
Field field3 = clazz.getDeclaredField("name"); // 獲得指定的域
這里同樣有個需要注意的地方站削,由于Java的安全機制原因坊萝,當我們要操作非public類型的域的時候,需要設置暫時關閉Java的安全檢驗,如下:
field3.setAccessible(true); //關閉安全校驗
之后我們就能對field3進行設置值了
field3.set(person, "xuhuanfeng"); //person同上
這樣屹堰,我們就能實現(xiàn)操作任意域了肛冶。
-
Annotation
相信經(jīng)過上面的例子,你已經(jīng)比較了解了扯键,所以對于Annotation這里就不再進行闡述了睦袖,操作跟上面基本都是類似的。
后記
Java的反射機制給開發(fā)者帶來了極大的便利荣刑,很多的框架也正是利用Java的反射機制從而實現(xiàn)了強大的生命力馅笙,相信看到這里,對于Java的反射厉亏,你已經(jīng)有比較好的認識了董习。