Java反射


一,反射是什么(反射是框架設計的靈魂)

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面試題與答案】整理推薦

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM