我所理解的JDK反射

1,什麼是Java的反射?
  經過對象所屬類的Class對象,能夠動態獲取運行時對象的信息,或執行對象的方法。java

2,Class對象是什麼?
  每個類在JVM中都對應惟一一個java.lang.Class對象,能夠經過newInstance()來調用無參構造建立一個實例對象。程序員

// 獲取類加載器
ClassLoader getClassLoader()  

// 獲取父類
Class<? super T> getSuperclass()  

// 獲取繼承父類時標明的泛型信息
Type getGenericSuperclass()

// 獲取該類實現的接口 
Class<?>[] getInterfaces() 

// 獲取實現父接口時標明的泛型信息
Type[] getGenericInterfaces()

// 獲取全部屬性  
Field[] getFields()

// 獲取當前類及全部繼承的父類的public修飾的方法。僅包括public  
Method[]getMethods()

// 獲取當前類的全部方法,包括public/private/protected/default修飾的方法,不包括繼承來的
Method[] getDeclaredMethods()

// 獲取全部構造方法  
Constructor<?>[] getConstructors()

// 獲取具體名稱的屬性
Field getField(String name)  

// 獲取具體的方法,僅包括public  
Method getMethod(String name, Class<?>... parameterTypes)

// 獲取具體的方法,包括public/private/protected/default修飾的方法,不包括繼承來的
Method getDeclaredMethod(String name, Class<?>... parameterTypes)  

// 獲取具體的構造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)  

// 是否被指定註解修飾
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)  

// 獲取全部類的註解
Annotation[] getAnnotations()  

// 獲取指定的註解
<A extends Annotation> A getAnnotation(Class<A> annotationClass)  

// 獲取指定的註解數組,包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<A extends Annotation> A getAnnotationsByType(Class<A> annotationClass)  

// 獲取指定的註解數組,不包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass)  

// 獲取修飾符
int getModifiers()  

// 獲取全類名
String getName()  

// 獲取簡稱
String getSimpleName()  

// 判斷是不是接口
boolean isInterface()  

// 判斷obj是不是該class的實例對象
boolean isInstance(Object obj)

3,如何獲取Class對象?spring

  1. Class.forName("com.test.A");
  2. a.getClass();
  3. com.test.A.class;
    區別詳見類加載機制

4,Method對象是什麼
Method對象表示Class中的方法信息。express

// 獲取單獨的方法名稱
String getName()

// 獲取完整的方法信息(包括修飾符、返回值、路徑、名稱、參數、拋出值)
String toGenericString()

// 獲取修飾符
int getModifiers()

// 獲取參數類型信息
Class<?>[] getParameterTypes()

// 獲取方法參數的泛型信息
Type[] getGenericParameterTypes()

// 獲取返回類型信息
Class<?> getReturnType()

// 獲取方法返回值的泛型信息
Type getGenericReturnType()

// 獲取異常信息
Class<?>[] getExceptionTypes()

// 是否被指定註解修飾
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

// 獲取方法註解
Annotation[] getAnnotations()

// 獲取指定的註解
<T extends Annotation> T getAnnotation(Class<T> annotationClass)

// 獲取方法參數的全部註解
Annotation[][] getParameterAnnotations()

// 獲取指定的註解數組,包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<T extends Annotation> T[] getAnnotationsByType(Class<A> annotationClass)

// 獲取指定的註解數組,不包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<A> annotationClass)

// 是不是橋接方法。JDK 1.5 引入泛型後,爲了使Java的泛型方法生成的字節碼和 1.5 版本前的字節碼相兼容,由編譯器自動生成的方法
boolean isBridge()

// 是不是默認方法。JDK1.8開始接口容許有默認方法
boolean isDefault()

// 是不是可變參方法。JDK1.5開始支持方法入參能夠是可變參
boolean isVarArgs()

// 是不是合成方法。JDK1.5開始支持枚舉類,這種類型不是程序員寫的,是編譯器生成的。涉及枚舉類的地方會由編譯器生成一些該類型方法
boolean isSynthetic()

// 反射執行obj對象的該方法,參數爲args
Object invoke(Object obj, Object... args)

5,Field對象是什麼?
Field對象表示Class中的屬性信息。數組

// 獲取屬性名
String getName()

// 獲取修飾符
int getModifiers()

// 是不是枚舉類型
boolean isEnumConstant()

// 是不是合成類型
boolean isSynthetic()

// 獲取屬性類型
Class<?>getType()

// 獲取屬性的泛型信息
Type getGenericType()

// 獲取obj對象的當前屬性值
Object get(Object obj)

// 將obj對象的當前屬性設置爲value
void set(Object obj, Object value)

// 是否被指定註解修飾
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

// 獲取屬性的全部註解
Annotation[] getAnnotations()

// 獲取屬性上的指定類型的註解
<T extends Annotation> T getAnnotation(Class<T> annotationClass)

// 獲取指定的註解數組,包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<T extends Annotation> T[] getAnnotationsByType(Class<A> annotationClass)

// 獲取指定的註解數組,不包括繼承父類的。JDK1.8支持,與@Repeatable()相關
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<A> annotationClass)

6,其餘好比Package對象,Constructor對象,URL對象,在反射中的使用頻率小,這裏就不研究了。.net

注意code

  1. 因爲編譯會進行泛型擦除致使編譯後的字節碼是沒有泛型信息的,因此運行期沒法經過反射獲得泛型信息。對象

  2. 訪問private的方法和變量須要設置method.setAccessible(true)或field.setAccessible(true)。blog

  3. invoke()執行方法時方法的參數類型及順序要正確。繼承

  4. 如何經過橋接方法獲取對應的實際方法呢?能夠查看spring中org.springframework.core.BridgeMethodResolver類的源碼。其實是經過判斷方法名、參數的個數以及泛型類型參數來獲取的。

反射get和set的3種方式

  1. 手動拼get和set的方法名,而後調用getMethod(name)再調用invoke()來執行
  2. 獲取屬性field,再get()、set()
  3. 使用java.beans.PropertyDescriptor
private Object getValueByReflect(Object obj, String expression) throws NoSuchFieldException, SecurityException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    Class<? extends Object> clazz = obj.getClass();
    Field field = clazz.getDeclaredField(expression);
    PropertyDescriptor pd=new PropertyDescriptor(field.getName(),clazz);
    Method method = pd.getReadMethod();
    return method.invoke(obj);
}

參考資料:

  1. 以上內容爲筆者平常瑣屑積累,已無從考究引用。若是有,請站內信提示。
相關文章
相關標籤/搜索