反射
1.1 反射定義
-
Oracle官方對反射的解釋:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control. # 翻譯 反射使Java代碼能夠發現有關已加載類的欄位、方法和建構式的資訊,并在安全限制內使用反射的欄位、方法和建構式對其底層對應項進行操作, API容納需要訪問目標物件的公共成員(基于其運行時類)或給定類宣告的成員的應用程式,它還允許程式抑制默認的反射訪問控制, -
通過反射,可以在程式運行時獲得程式或程式集中每一個型別的成員和成員的資訊,一般來說,程式中的物件型別在編譯期間就確定了,而Java的反射機制可以動態創建物件并呼叫其屬性,這樣的物件的型別在編譯期間是未知的,因此可以通過反射機制直接創建物件,
-
Java反射機制的核心是在程式運行時動態加載類并獲取類的詳細資訊,從而操作類或物件的屬性和方法,本質是JVM得到class物件之后,再通過class物件進行反編譯,從而獲取物件的各種資訊
-
Java屬于先編譯再運行的語言,程式中物件的型別在編譯期間就確定下來了,而當程式在運行時可能需要動態加載某些類,這些類因為之前用不到,所以乜有被加載到JVM中,通過反射,可以在運行時動態的創建物件并呼叫其屬性,不需要提前在編譯期知道運行的物件是哪個,
1.2 反射優缺點
- 優點:程式運行時獲得類的各項資訊,進行反編譯,對于Java這種先編譯再運行的語言,能夠很方便的創建靈活的代碼,這些代碼在運行時裝配,無需在組件之間進行源代碼的鏈接,更容易實作面向物件,
- 缺點:
- 反射會消耗一定的系統資源,因此如果不需要動態的創建一個物件,就不需要反射
- 反射呼叫方法可以忽略權限檢查,可能會因為破壞了封裝性導致安全問題
1.3 反射常見用途
- 反射機制訪問物件的屬性、方法等,
- JDBC連接資料庫,使用Class.forName()通過反射加載資料庫驅動程式
- SpringIOC容器的xml配置裝配Bean物件:將專案中xml或者properties組態檔載入記憶體中,然后決議xml或者properties里面的內容,得到對應類的位元組碼字串以及相關的屬性資訊,使用反射機制,根據這個字串獲得某個類的class示例,動態配置實體的屬性
- 自定義注解生效(反射+AOP)
- 第三方核心框架 MyBatis orm
1.4 反射常用類和方法
- 類
- Class類代表類的物體,在運行的Java應用程式中表示類或介面
- Field類代表類的成員變數(成員變數也稱為類的蘇醒)
- Method類表示類的方法
- Constructor類代表類的構造方法
- 方法
- etField、getMethod、getConstructor方法可以獲得指定名稱的域、方法和構造器
- getFields、getMethods、getConstructors方法可以獲得類中的public域、方法和構造器陣列,其中包括父類的公有成員
- getDeclaredFields、getDeclaredMethods、getDeclaredConstructors可以獲得類中宣告的全部域、方法和構造器,其中包括私有和受保護的成員,但是不包括父類的成員,
1.5 反射常用API
1.5.1 獲取類的Class物件
-
特點
- Class類內部只有一個私有的建構式,并且只能夠被Java虛擬機來呼叫創建類的實體,
- 在程式運行期間,一個類只有會存在一個與之對應的Class物件
-
代碼
// 方式一:呼叫實體物件的getClass()方法 Children children = new Children(); Class<? extends Children> class1 = children.getClass(); // com.fc.reflectionandannotation.reflection.Children System.out.println(class1.getName()); // 方式二:通過類名.class獲取 Class<Children> class2 = Children.class; // com.fc.reflectionandannotation.reflection.Children System.out.println(class2.getName()); // (最常用)方式三:呼叫Class.forName(String className)靜態方法 Class<?> class3 = Class.forName("com.fc.reflectionandannotation.reflection.Children"); System.out.println(class3.getName()); System.out.println(class1 == class2); System.out.println(class1 == class3);- [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HZFZDx0p-1639899649676)(https://gitee.com/FcleverSD/elastic-search-pic/raw/master/20210810140920.png"/>
1.5.5 反射越過泛型檢查
-
泛型用在編譯期,在通過編譯之后泛型會被擦除,所以可以通過反射越過泛型檢查,
-
代碼
List<String> list = new ArrayList<>(); list.add("ceshilist"); //list.add(1); // 1.反射獲取Class物件 Class<? extends List> clazz = list.getClass(); // 獲取add方法 Method add = clazz.getDeclaredMethod("add", Object.class); // 執行add方法,插入一個資料 Object invoke = add.invoke(list, 1); // 列印當前list的大小 System.out.println(list.size()); -
說明
-
構建泛型為String的List集合,然后通過反射插入Integer型別的資料,因為泛型在編譯期進行檢查,在實際運行程序中可以越過
-
檢查,
-
代碼
List<String> list = new ArrayList<>(); list.add("ceshilist"); //list.add(1); // 1.反射獲取Class物件 Class<? extends List> clazz = list.getClass(); // 獲取add方法 Method add = clazz.getDeclaredMethod("add", Object.class); // 執行add方法,插入一個資料 Object invoke = add.invoke(list, 1); // 列印當前list的大小 System.out.println(list.size()); -
說明
-
構建泛型為String的List集合,然后通過反射插入Integer型別的資料,因為泛型在編譯期進行檢查,在實際運行程序中可以越過
-
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/387073.html
標籤:其他
上一篇:DBeaver EE 21.3.x Macos 安裝及Active
下一篇:Python下實作Tesseract OCR訓練字符庫(OpenCV-python邊緣檢測代替jTessBoxEditor手動矯正)
