反射获取list泛型_Android 从浅到懂使用反射机制
定義
Java 反射機制是發生在運行狀態中,對于任何一個類,都能夠知道這個類的所有屬性和方法;對于任何一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為 Java 語言的反射機制。
使用場景
反射是在運行時獲取確定類型,綁定對象。
常見的兩個使用場景
在運行時獲取類
這里的運行時指的是程序在運行后。相應的還有編譯時,編譯時是編譯器將源代碼翻譯成機器能識別的代碼。
舉個例子說明編譯時和運行時的區別:
泛型擦除
示例:設定集合是Int,但是最后輸出的集合中包含String,這就實現了泛型擦除功能。
val?list?=?arrayListOf(1,2,3)val?clz?=?Class.forName("java.util.ArrayList")
val?method?=?clz.getMethod("add",?Object::class.java)method.invoke(list,"hhh")Log.e(TAG,"list:${list.toString()}")
輸出:
list:[1,?2,?3,?hhh]
反射的利弊
利
- 運行時類型的判斷
- 動態類加載,動態代理使用反射。
弊
- 性能問題,反射相當于一系列解釋操作。
- JVM 不會去優化這部分代碼
- 代碼不易閱讀
為什么會出現性能問題?
invoke方法源碼:
class?Class?{????@CallerSensitive
????public?Method?getMethod(String?name,?Class>...?parameterTypes)throws?NoSuchMethodException,?SecurityException?{
????????Objects.requireNonNull(name);
????????SecurityManager?sm?=?System.getSecurityManager();
????????if?(sm?!=?null)?{
????????????//?1.?檢查方法權限
????????????checkMemberAccess(sm,?Member.PUBLIC,?Reflection.getCallerClass(),?true);
????????}
????????//?2.?獲取方法
????????Method?method?=?getMethod0(name,?parameterTypes);
????????if?(method?==?null)?{
????????????throw?new?NoSuchMethodException(methodToString(name,?parameterTypes));
????????}
????????//?3.?返回方法的拷貝
????????return?getReflectionFactory().copyMethod(method);
????}
????@CallerSensitive
????public?Method?getDeclaredMethod(String?name,?Class>...?parameterTypes)throws?NoSuchMethodException,?SecurityException?{
????????Objects.requireNonNull(name);
????????SecurityManager?sm?=?System.getSecurityManager();
????????if?(sm?!=?null)?{
????????????//?1.?檢查方法權限
????????????checkMemberAccess(sm,?Member.DECLARED,?Reflection.getCallerClass(),?true);
????????}
????????//?2.?獲取方法
????????Method?method?=?searchMethods(privateGetDeclaredMethods(false),?name,?parameterTypes);
????????if?(method?==?null)?{
????????????throw?new?NoSuchMethodException(methodToString(name,?parameterTypes));
????????}
????????//?3.?返回方法的拷貝
????????return?getReflectionFactory().copyMethod(method);
????}
}
如何使用
想要使用反射機制,就必須要先獲取到該類的字節碼文件對象(.class),通過字節碼文件對象,就能夠通過該類中的方法獲取到我們想要的所有信息(方法,屬性,類名,父類名,實現的所有接口等等),每一個類對應著一個字節碼文件也就對應著一個Class類型的對象。
獲取字節碼文件對象
- 1、根據類名:類名.class
- 2、根據對象:對象.getClass()
- 3、根據全限定類名:Class.forName(全限定類名)
常用的是第一種。
獲取構造函數
構造函數分為兩種:帶參和不帶參
- 獲取不帶參構造函數
Constructor?constructor?=?classs.getDeclaredConstructor();
Object?user?=?constructor.newInstance();
- 獲取帶參構造函數
Constructor?constructor?=?classs.getConstructor(int.class,String.class);
Object?user?=?constructor.newInstance(1,"張三");
獲取成員變量
成員變量一般為公有和私有
- 獲取公有成員變量
Constructor?constructor?=?classs.getConstructor();
Object?user?=?constructor.newInstance();
Field?declaredField?=?classs.getField("userName");
//?賦新值
declaredField.set(user,?"李四");
- 獲取私有成員變量
Constructor?constructor?=?classs.getConstructor();
Object?user?=?constructor.newInstance();
Field?declaredField?=?classs.getDeclaredField("userName");
//?因為屬性是私有的,所有需要打開可見權限
declaredField.setAccessible(true);
//?賦新值
declaredField.set(user,?"李四");
獲取方法
成員方法一般為公有和私有,同時方法也分有參和無參
- 獲取公有成員無參方法
Constructor?constructor?=?classs.getConstructor();
Object?user?=?constructor.newInstance();
Method?method?=?classs.getMethod("getUserName");
method.invoke(user);
- 獲取公有成員有參方法
Constructor?constructor?=?classs.getConstructor();
Object?user?=?constructor.newInstance();
Method?method?=?classs.getMethod("getUserName",?String.class);
method.invoke(user,?"王五");
- 獲取私有成員無參方法
Constructor?constructor?=?classs.getConstructor();
Object?user?=?constructor.newInstance();
Method?method?=?classs.getDeclaredMethod("getUserName");
//?因為屬性是私有的,所有需要打開可見權限
method.setAccessible(true);
method.invoke(user);
- 獲取私有成員有參方法
Constructor?constructor?=?classs.getConstructor();
Object?user?=??constructor.newInstance();
Method?method?=?classs.getDeclaredMethod("getUserName",String.class);
//?因為屬性是私有的,所有需要打開可見權限
method.setAccessible(true);
method.invoke(user,?"王五");
Tip
總結
反射的作用是在運行時動態獲取對象信息。
實現步驟:
沒有 Declared 前綴會返回所有的 public 方法,包括父類的方法。而加 Declared 前綴會返回所有自己定義的方法,public,protected,private 都在此,但是不包括父類的方法。
這也正是 getMethod 和 getDeclaredMethod 的區別。
- 獲取私有構造函數
Constructor?constructor?=?classs.getDeclaredConstructor();
//?因為屬性是私有的,所有需要打開可見權限
constructor.setAccessible(true);
Object?user?=?constructor.newInstance();
- 獲取私有成員變量
Field?declaredField?=?classs.getDeclaredField("userName");
//?因為屬性是私有的,所有需要打開可見權限
declaredField.setAccessible(true);
- 獲取私有成員方法
Method?method?=?classs.getDeclaredMethod("getUserName");
//?因為屬性是私有的,所有需要打開可見權限
method.setAccessible(true);
反射耗時的原因:
- invoke方法需要做封裝和解封操作
- 需要類型檢查、權限檢查
- 需要校驗參數
- 需要檢查方法的可見性
- JVM無法做優化
參考
- Reflection:Java反射機制的應用場景
- 深入淺出Java反射原理和使用場景
- java反射機制詳解
- Java 反射 -超詳細講解(附源碼)
- java反射為什么慢
- 強大的反射庫 FreeReflection
總結
以上是生活随笔為你收集整理的反射获取list泛型_Android 从浅到懂使用反射机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 吉普寨是哪里的国家 吉普寨属于哪里的国家
- 下一篇: toastutils报错_史上最好用的A