react-keep-alive
阿新 • • 發佈:2020-09-23
反射
反射簡介
java的反射就是通過Class來在執行時獲取類的完整結構資訊 & 呼叫物件的方法。正常情況下,Java
類在編譯前,就已經被載入到JVM
中;而反射機制使得程式執行時還可以動態地去操作類的變數、方法等資訊。
反射的本質是當一個類被載入以後,Java虛擬機器就會自動產生一個 Class物件。通過這個 Class物件我們就能獲得載入到虛擬機器當中這個Class物件對應的方法、成員以及構造方法的宣告和定義等資訊。
優點是靈活在執行時才動態建立&獲取,缺點則是效率低,容易破壞類結構(因為繞過了原始碼容易干擾類原有內部邏輯)。
效率低主要是由以下幾個方面造成:
- 反射呼叫過程中會產生大量的臨時物件,這些物件會佔用記憶體,可能會導致頻繁 gc,從而影響效能。
- 反射呼叫方法時會從方法陣列中遍歷查詢,並且會檢查可見性等操作會耗時。
- 反射呼叫時編譯器難以對動態呼叫的程式碼提前做優化。
- 反射一般會涉及自動裝箱/拆箱和型別轉換,都會帶來一定的資源開銷
反射使用
大致分為以下幾個方面:
- 獲取Constructor類物件
<-- 1. 獲取類的建構函式(傳入建構函式的引數型別)->> // a. 獲取指定的建構函式 (公共 / 繼承) Constructor<T> getConstructor(Class<?>... parameterTypes) // b. 獲取所有的建構函式(公共 / 繼承) Constructor<?>[] getConstructors(); // c. 獲取指定的建構函式 ( 不包括繼承) Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) // d. 獲取所有的建構函式( 不包括繼承) Constructor<?>[] getDeclaredConstructors(); // 最終都是獲得一個Constructor類物件 // 特別注意: // 1. 不帶 "Declared"的方法支援取出包括繼承、公有(Public) & 不包括有(Private)的建構函式 // 2. 帶 "Declared"的方法是支援取出包括公共(Public)、保護(Protected)、預設(包)訪問和私有(Private)的構造方法,但不包括繼承的建構函式 // 下面同理
- 獲取Method類物件
<-- 2. 獲取類的屬性(傳入屬性名) -->
// a. 獲取指定的屬性(公共 / 繼承)
Field getField(String name) ;
// b. 獲取所有的屬性(公共 / 繼承)
Field[] getFields() ;
// c. 獲取指定的所有屬性 (不包括繼承)
Field getDeclaredField(String name) ;
// d. 獲取所有的所有屬性 (不包括繼承)
Field[] getDeclaredFields() ;
// 最終都是獲得一個Field類物件
- 獲取Field類物件
<-- 3. 獲取類的方法(傳入方法名 & 引數型別)-->
// a. 獲取指定的方法(公共 / 繼承)
Method getMethod(String name, Class<?>... parameterTypes) ;
// b. 獲取所有的方法(公共 / 繼承)
Method[] getMethods() ;
// c. 獲取指定的方法 ( 不包括繼承)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) ;
// d. 獲取所有的方法( 不包括繼承)
Method[] getDeclaredMethods() ;
// 最終都是獲得一個Method類物件
- 其他常用方法
getSuperclass();
// 返回父類
String getName();
// 作用:返回完整的類名(含包名,如java.lang.String )
Object newInstance();
總結來說分為帶 "Declared"和不帶 "Declared",不帶Declared的方法只能獲取公有屬性以及從父類繼承的,帶Declared的則只能訪問自己定義的屬性(但是可以獲取私有屬性)。還有可以根據是否提供引數分類,帶引數的方法一般是根據引數匹配符合的屬性,不帶引數的獲取方法會返回所有符合的屬性。
當獲取到Constructor、Method、Field之後我們可以根據獲取的物件做進一步的獲取資訊或操作
<-- 1. 通過Constructor 類物件獲取類建構函式資訊 -->
String getName();// 獲取構造器名
Class getDeclaringClass();// 獲取一個用於描述類中定義的構造器的Class物件
int getModifiers();// 返回整型數值,用不同的位開關描述訪問修飾符的使用狀況
Class[] getExceptionTypes();// 獲取描述方法丟擲的異常型別的Class物件陣列
Class[] getParameterTypes();// 獲取一個用於描述引數型別的Class物件陣列
<-- 2. 通過Field類物件獲取類屬性資訊 -->
String getName();// 返回屬性的名稱
Class getDeclaringClass(); // 獲取屬性型別的Class型別物件
Class getType();// 獲取屬性型別的Class型別物件
int getModifiers(); // 返回整型數值,用不同的位開關描述訪問修飾符的使用狀況
Object get(Object obj) ;// 返回指定物件上 此屬性的值
void set(Object obj, Object value) // 設定 指定物件上此屬性的值為value
<-- 3. 通過Method 類物件獲取類方法資訊 -->
String getName();// 獲取方法名
Class getDeclaringClass();// 獲取方法的Class物件
int getModifiers();// 返回整型數值,用不同的位開關描述訪問修飾符的使用狀況
Class[] getExceptionTypes();// 獲取用於描述方法丟擲的異常型別的Class物件陣列
Class[] getParameterTypes();// 獲取一個用於描述引數型別的Class物件陣列
<--額外:java.lang.reflect.Modifier類 -->
// 作用:獲取訪問修飾符
static String toString(int modifiers)
// 獲取對應modifiers位設定的修飾符的字串表示
static boolean isXXX(int modifiers)
// 檢測方法名中對應的修飾符在modifiers中的值
陣列與列舉的反射
//建立元素型別、元素長度指定的陣列
public static Object newInstance(Class<?> componentType, int length)
//建立多維度的陣列,dimensions可連續傳遞多個,分別代表不同維度
public static Object newInstance(Class<?> componentType, int... dimensions)
//獲取指定陣列的對應索引的值
public static native Object get(Object array, int index)
//賦值給指定陣列的對應索引下的值
public static native void set(Object array, int index, Object value)
//獲取陣列長度
public static native int getLength(Object array)
//獲取當前列舉型別Class的所有定義的列舉常量
public T[] getEnumConstants()
String[] strArr = new String[10];
int[][] twoDimArr = new int[3][2];
int[] oneDimArr = new int[10];
Class<? extends String[]> strArrCls = strArr.getClass();
Class<? extends int[][]> twoDimArrCls = twoDimArr.getClass();
Class<? extends int[]> oneDimArrCls = oneDimArr.getClass();
獲取基本資料型別的Class
//基本型別的class即為對應的包裝型別
Class<Integer> intCls = int.class;
Class<Byte> byteCls = byte.class;
Class<Character> charCls = char.class;
Class<Double> doubleCls = double.class;
//void也是一種特殊的型別,返回的也是對應的包裝類Void
Class<Void> voidCls = void.class;
反射應用
反射是Android原始碼裡面應用最多的地方,小到xml的解析,大到dex檔案的載入,application的啟動,均大量運用了反射。
- 反射生成物件、執行方法、獲取類資訊
- 工廠模式優化
- 動態代理