一,反射是什么(反射是框架設計的靈魂)
1,JAVA反射機制是在運行狀態中
對於任意一個類,都能夠知道這個類的所有屬性和方法;
對於任意一個對象,都能夠調用它的任意一個方法和屬性;
這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
2,反射提供的功能:
- 在運行時判斷任意一個對象所屬的類
- 在運行時構造任意一個類的對象
- 在運行時判斷任意一個類所具有的成員變量和方法
- 在運行時調用任意一個對象的方法
(要想解剖一個類,必須先要獲取到該類的字節碼文件對象(class)。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象.)
3,關於class對象和這個class類
- Class對象的由來是將class文件讀入內存,並為之創建一個Class對象
4,class類 :代表一個類,是Java反射機制的起源和入口
- 用於獲取與類相關的各種信息, 提供了獲取類信息的相關方法
-
Class類繼承自Object類
-
Class類是所有類的共同的圖紙
-
每個類有自己的對象,同時每個類也看做是一個對象,有共同的圖紙Class,存放類的結構信息,能夠通過相應方法取出相應的信息:類的名字、屬性、方法、構造方法、父類和接口。
Class 類的實例表示正在運行的 Java 應用程序中的類和接口。也就是jvm中有N多的實例每個類都有該Class對象。
Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了。
沒有公共的構造方法,方法共有64個太多了。下面用到哪個就詳解哪個吧
5,反射的使用場景
- Java編碼時知道類和對象的具體信息,此時直接對類和對象進行操作即可,無需反射
- 如果編碼時不知道類或者對象的具體信息,此時應該使用反射來實現
比如類的名稱放在XML文件中,屬性和屬性值放在XML文件中,需要在運行時讀取XML文件,動態獲取類的信息
在編譯時根本無法知道該對象或類可能屬於哪些類,程序只依靠運行時信息來發現該對象和類的真實信息
二,獲取反射入口(class對象)的三種方法
要想操作反射,必須先拿到反射的入口
1,通過通過Class.forName("全類名")
try { Class<?> perClazz = Class.forName("reflect_fanshe.Person"); System.out.println(perClazz); } catch (ClassNotFoundException e) { e.printStackTrace();
2,類名.class
Class<?> perClazz2 = Person.class;
3,對象.getClass()
Person person = new Person(); Class<?> perClazz3 = person.getClass();
三,根據反射入口對象(class)獲取類的各種信息
可以用一個類的反射入口class對象獲取類的所有信息
- 例1:perClazz.getMethods() 獲取此類的所有public方法(父類的,實現接口的,自己的)
Class<?> perClazz = null; try { perClazz = Class.forName("reflect_fanshe.Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Method[] methods = perClazz.getMethods(); //遍歷所有方法 for (Method method : methods) { System.out.println(method); } }
- 例2:獲取所有的構造方法
- 例3: 獲取父類
- 例4:獲取當前類(只有本類的)的所有方法和屬性,包括私有的
- 重要:可以獲取當前類的對象,並通過對象調用類的方法
四,通過反射獲取對象的實例,並操作對象
1,class.newInstance() ,並強轉類型,然后就可以操作對象了,主要是調用方法。
2,操作屬性,可以操作類里面的public屬性和private屬性
如果屬性是private,正常情況下是不允許外界操作屬性值,這里可以用Field類的setAccessible(true)方法,暫時打開操作的權限
調用方法也一樣,可以調用私有的方法,null是因為這個方法沒有參數
五,在 程序執行中,動態的決定調用的類,以及方法
在本例中,程序執行之前,程序根本不知道具體的類和方法名是什么,需要執行時解析properties文件,但是反射就可以辦到。
配置文件:
反射機制:
Java內置9大的Class實例
對於對象來說,可以直接使用對象.getClass()或者Class.forName(className); 類名.class都可以獲取Class實例.
但是我們的基本數據類型,就沒有類的權限定名,也沒有getClass方法.
問題:那么如何使用Class類來表示基本數據類型的Class實例?
byte,short,int,long,char,float,double,boolean ,void關鍵字
上述8種類型和void關鍵字,都有class屬性.
表示int的Class對象: Class clz = int.class;
表示boolean的Class對象: boolean.class;
void: Class clz = void.class;
所有的數據類型都有class屬性,表示都是Class對象.
思考:
int的包裝類是Integer
Integer.class ==?== int.class
結果是false,說明是兩份字節碼.
Integer 和int是同一種數據類型嗎? 不是
但是在八大基本數據類型的包裝類中都有一個常量:TYPE
TYPE表示的是該包裝類對應的基本數據類型的Class實例.
如:Integer.TYPE----->int.class
Integer.TYPE==int.class;//YES
Integer.TYPE == Integer.class;//ERROR
數組的Class實例
:String[] sArr1 = {"A","C"};
String[] sArr2 = {};
String[][] sArr = {};
int[] sArr = {};
表示數組的Class實例:
String[] sArr1 = {"A","C"};
Class clz = String[].class;//此時clz表示就是一個String類型的一位數組類型
所有具有相同元素類型和維數的數組才共享同一份字節碼(Class對象);
注意:和數組中的元素沒有一點關系.
關於setAccessible的官方說明:
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html
Java反射機制提供的setAccessible()方法可以取消Java的權限控制檢查。
使用場景
- 在編譯時無法知道該對象或類可能屬於哪些類,程序在運行時獲取對象和類的信息
作用
- 通過反射可以使程序代碼訪問裝載到 JVM 中的類的內部信息,獲取已裝載類的屬性信息、方法信息
優點
- 提高了 Java 程序的靈活性和擴展性,降低耦合性,提高自適應能力。
- 允許程序創建和控制任何類的對象,無需提前硬編碼目標類
- 應用很廣,測試工具、框架都用到了反射
缺點
- 性能問題:反射是一種解釋操作,遠慢於直接代碼。因此反射機制主要用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用
- 模糊程序內部邏輯:反射繞過了源代碼,無法再源代碼中看到程序的邏輯,會帶來維護問題
- 增大了復雜性:反射代碼比同等功能的直接代碼更復雜
【Java面試題與答案】整理推薦