一、理解
概念
反射是JAVA的一個機制。
在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制。
每個類被加載之后,系統(tǒng)就會為該類生成一個對應(yīng)的Class對象。通過該Class對象就可以訪問到JVM中的這個類。
應(yīng)用
1. 獲取程序在運行時刻的內(nèi)部結(jié)構(gòu)
這對于程序的檢查工具和調(diào)試器來說,是非常實用的功能。只需要短短的十幾行代碼,就可以遍歷出來一個Java類的內(nèi)部結(jié)構(gòu),包括其中的構(gòu)造方法、聲明的域和定義的方法等。這不得不說是一個很強大的能力。只要有了java.lang.Class類 的對象,就可以通過其中的方法來獲取到該類中的構(gòu)造方法、域和方法。對應(yīng)的方法分別是getConstructor、getField和getMethod。這三個方法還有相應(yīng)的getDeclaredXXX版本,區(qū)別在于getDeclaredXXX版本的方法只會獲取該類自身所聲明的元素,而不會考慮繼承下來的。Constructor、Field和Method這三個類分別表示類中的構(gòu)造方法、域和方法。這些類中的方法可以獲取到所對應(yīng)結(jié)構(gòu)的元數(shù)據(jù)。
2. 在運行時刻對一個Java對象進(jìn)行操作
這些操作包括動態(tài)創(chuàng)建一個Java類的對象,獲取某個域的值以及調(diào)用某個方法。在Java源代碼中編寫的對類和對象的操作,都可以在運行時刻通過反射API來實現(xiàn)。
二、使用
取得Class對象
每個類被加載之后,系統(tǒng)就會為該類生成一個對應(yīng)的Class對象。通過該Class對象就可以訪問到JVM中的這個類。
在Java程序中獲得Class對象通常有如下三種方式:
- 使用 Class 類的forName(String clazzName)靜態(tài)方法。該方法需要傳入字符串參數(shù),該字符串參數(shù)的值是某個類的全限定名(必須添加完整包名)。
- 調(diào)用某個類的class屬性來獲取該類對應(yīng)的 Class 對象。
- 調(diào)用某個對象的getClass()方法。該方法是java.lang.Object類中的一個方法。
//第一種方式 通過Class類的靜態(tài)方法——forName()來實現(xiàn)
class1 = Class.forName("com.lvr.reflection.Person");
//第二種方式 通過類的class屬性
class1 = Person.class;
//第三種方式 通過對象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
對于方式一和方式二都是直接根據(jù)類來取得該類的 Class 對象,相比之下,方式二有如下的兩種優(yōu)勢:
- 代碼更安全。程序在編譯階段就能夠檢查需要訪問的 Class 對象是否存在。
- 線程性能更好。因為這種方式無須調(diào)用方法,所以性能更好。
可以通過類的類類型創(chuàng)建該類的對象實例。
//Class.newInstance();
Foot foot = (Foot) c1.newInstance();
從class中獲取信息(常用)
一旦獲得了某個類所對應(yīng)的Class 對象之后,就可以調(diào)用 Class 對象的方法來獲得該對象的和該類的真實信息了。
1. 獲取 Class 對應(yīng)類的成員變量
Field[] getDeclaredFields(); // 獲取 Class 對象對應(yīng)類的所有屬性,與成員變量的訪問權(quán)限無關(guān)。
Field[] getFields(); // 獲取 Class 對象對應(yīng)類的所有 public 屬性。
Field getDeclaredField(String name); // 獲取 Class 對象對應(yīng)類的指定名稱的屬性,與成員變量的訪問權(quán)限無關(guān)。
Field getField(String name); // 獲取 Class 對象對應(yīng)類的指定名稱的 public 屬性。
2. 獲取 Class 對應(yīng)類的方法
Method[] getDeclaredMethods(); // 獲取 Class 對象對應(yīng)類的所有聲明方法,于方法的訪問權(quán)限無關(guān)。
Method[] getMethods(); // 獲取 Class 對象對應(yīng)類的所有 public 方法,包括父類的方法。
Method getMethod(String name, Class<?>...parameterTypes); // 返回此 Class 對象對應(yīng)類的、帶指定形參列表的 public 方法。
Method getDeclaredMethod(String name, Class<?>...parameterTypes); // 返回此 Class 對象對應(yīng)類的、帶指定形參列表的方法,與方法的訪問權(quán)限無關(guān)。
3. 獲取 Class 對應(yīng)類的構(gòu)造函數(shù)
Constructor<?>[] getDeclaredConstructors(); // 獲取 Class 對象對應(yīng)類的所有聲明構(gòu)造函數(shù),于構(gòu)造函數(shù)的訪問權(quán)限無關(guān)。
Constructor<?>[] getConstructors(); // 獲取 Class 對象對應(yīng)類的所有 public 構(gòu)造函數(shù)。
Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes); // 返回此 Class 對象對應(yīng)類的、帶指定形參列表的構(gòu)造函數(shù),與構(gòu)造函數(shù)的訪問權(quán)限無關(guān)。
Constructor<T> getConstructor(Class<?>...parameterTypes); // 返回此 Class 對象對應(yīng)類的、帶指定形參列表的 public 構(gòu)造函數(shù)。
(不常用)
4. 獲取 Class 對應(yīng)類的 Annotation(注釋)
<A extends Annotation>A getAnnotation(Class<A> annotationClass); // 嘗試獲取該 Class 對對象對應(yīng)類存在的、指定類型的 Annotation;如果該類型的注解不存在,則返回 null。
<A extends Annotation>A getDeclaredAnnotation(Class<A> annotationClass); // 這是Java8新增的方法,該方法嘗試獲取直接修飾該 Class 對象對應(yīng)類、指定類型的Annotation;如果該類型的注解不存在,則返回 null。
Annotation[] getAnnotations(); // 返回修飾該 Class 對象對應(yīng)類存在的所有Annotation。
Annotation[] getDeclaredAnnotations(); // 返回直接修飾該 Class 對應(yīng)類的所有Annotation。
<A extends Annotation>A[] getAnnotationsByType(Class<A> annotationClass); // 獲取修飾該類的、指定類型的多個Annotation。
<A extends Annotation>A[] getDeclaredAnnotationsByType(Class<A> annotationClass); // 獲取直接修飾該類的、指定類型的多個Annotation。
5. 獲取 Class 對應(yīng)類的內(nèi)部類
Class<?>[] getDeclaredClasses(); // 返回該 Class 對象對應(yīng)類包含的全部內(nèi)部類。
6. 獲取 Class 對應(yīng)類的外部類
Class<?> getDeclaringClass(); // 返回該 Class 對象對應(yīng)類所在的外部類。
7. 獲取 Class 對應(yīng)類所實現(xiàn)的接口
Class<?>[] getInterfaces();
8. 獲取 Class 對應(yīng)類所繼承的父類
Class<? super T> getSuperClass();
9. 獲取 Class 對應(yīng)類的修飾符、所在包、類名等基本信息
int getModifiers(); // 返回此類或接口的所有修飾符。修飾符由 public、protected、private、final、static、abstract 等對應(yīng)的常量組成,返回的整數(shù)應(yīng)使用 Modifier 工具類的方法來解碼,才可以獲取真實的修飾符。
Package getPackage() // 獲取該類的包。
String getName() // 以字符串的形式返回此 Class 對象所表示的類的名稱。
String getSimpleName() // 以字符串的形式返回此 Class 對象所表示的類的簡稱。
10. 判斷該類是否為接口、枚舉、注解類型等
boolean isAnnotation() // 返此 Class 對象是否是一個注解類型(由@interface定義)。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 判斷此 Class 對象是否使用了Annotation修飾。
boolean isAnonymousClass() // 此 Class 對象是否是一個匿名類。
boolean isArray() //此 Class 對象是否是一個數(shù)組。
boolean isEnum() // 此 Class 對象是否是一個枚舉(由 enum 關(guān)鍵字定義)。
boolean isInterface() // 此 Class 對象是否是一個接口(由 interface 關(guān)鍵字定義)。
boolean isInstance(Object obj) // 判斷 obj 是否是此 Class 對象的實例。該方法完全可以替代 instanceof 操作符。