1. 程式人生 > >【java.lang.reflect】反射機制應用及詳解

【java.lang.reflect】反射機制應用及詳解

最近也是面試的時候問道一個問題,如何將一個java物件轉換為json字串,一聽到的時候沒有任何思路,之前也有接觸過fastjson,知道就是用這個jar包來處理的,但是具體如何執行原理並不瞭解,導致面試說不出來,面試官提到fastjson其實就是利用反射來獲取這個物件對應的資訊,然後轉化,於是對反射機制做一個詳細的掌握。

一、什麼是反射機制?

java的反射機制就是在java程式執行中,可以獲得任何一個類的所有屬性和方法。對於任意一個物件,可以呼叫其成員和方法。這種動態獲取類資訊和呼叫屬性和方法的機制叫做java的反射機制。

要剖析一個類,最關鍵的是獲取其位元組碼檔案(.class)也就是Class物件資訊。

下面我們通過java的類載入機制來分析一下Class物件怎麼來的:

反射就是把java類中的各種成分對映成一個個的Java物件

例如:一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把個個組成部分對映成一個個物件。(其實:一個類中這些成員方法、構造方法、在加入類中都有一個類來描述)

如圖是類的正常載入過程:反射的原理在與class物件。

熟悉一下載入的時候:Class物件的由來是將class檔案讀入記憶體,併為之建立一個Class物件。

整個過程其實就是類載入的載入過程,通過類的全限定名將磁碟中的class二進位制檔案載入到記憶體中,然後將其靜態儲存結構轉化為方法區可以執行的資料結構,最後生成一個Class物件作為訪問的入口。(這裡就生成了Class物件就是包含了類的資訊)

二、檢視Class類在java中的api詳解(1.7的API)

如何閱讀java中的api詳見java基礎之——String字串處理

Class 類的例項表示正在執行的 Java 應用程式中的類和介面。也就是jvm中有N多的例項每個類都有該Class物件。(包括基本資料型別)

Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及通過呼叫類載入器中的defineClass方法自動構造的。也就是這不需要我們自己去處理建立,JVM已經幫我們建立好了。

三、反射的使用

反射的使用依賴的關鍵就是Class物件,不管需要什麼樣的操作,都需要先拿到對應類或者物件的Class物件才能起作用。

1.獲取Class物件的三種方法

  1. 通過靜態.class方法獲取,任何資料型別(包括基本資料型別)都有靜態class() 方法直接獲取Class物件,但是沒有這個類就無法呼叫
  2. 通過getClass()方法,該物件的getClass()方法可以獲取該類的Class檔案,需要匯入物件
  3. 通過Class.forName(String name) 通過一個類的全限定名,拿到其Class物件,不需要任何支援 

反射的常用類和函式:Java反射機制的實現要藉助於4個類:Class,Constructor,Field,Method;其中class代 表的是類物件,Constructor-類的構造器物件,Field-類的屬性物件,Method-類的方法物件,通過這四個物件我們可以粗略的看到一個類的各個組成部分。其中最核心的就是Class類,它是實現反射的基礎

2.通過反射獲取建構函式

測試類:

public class BeanDemo {
    private  int age;
    private  String name;
    public  String  pub;
    String tall;
    char sex;

    public String getTall() {
        return tall;
    }

    public void setTall(String tall) {
        this.tall = tall;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    /**唯一的方法
     * */
    public void speak(String  name){

        System.out.println("我的名字是"+name);

    }

    public BeanDemo() {
    }

    /**建構函式
     * */
    private BeanDemo(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("私有建構函式呼叫:"+name+age);
    }

    public BeanDemo(String name) {
        this.name = name;
        System.out.println("呼叫建構函式:"+name);
    }

    public BeanDemo(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 建構函式:

        /**一:通過反射獲取構造方法
         *     1.通過getConstructors() 所有公有的構造方法
         * */
        Constructor[] constructors  = bean.getConstructors();
        System.out.println("====================================getConstructors()獲取公有構造方法==========================");
        for (Constructor c : constructors){
            System.out.println("公有建構函式有:"+c);
        }
        System.out.println("====================================getDeclaredConstructors()獲取私有,protected,預設,公有構造方法(也就是所有的構造方法)==========================");
        /** 2.通過getDeclaredConstructors() 獲取所有
         * */
        Constructor[] decCon = bean.getDeclaredConstructors();
        for (Constructor c : decCon){
            System.out.println("全部建構函式有:"+c);
        }
        System.out.println("====================================getConstructor(null) 無參建構函式 可以根據傳入的引數型別獲取對應的建構函式==========================");

        Constructor nullCon = bean.getConstructor(null);
        Constructor intCon = bean.getConstructor(String.class);
        System.out.println(nullCon);
        System.out.println(intCon);
        System.out.println("====================================getConstructor(null) 呼叫建構函式==========================");
        Object obj = intCon.newInstance("hhh");//呼叫建構函式,就是利用建構函式物件,建立例項
        //若是私有建構函式,加上setAccessible(true)  要先用getDeclaredConstructor() 
        Constructor intStrCon = bean.getDeclaredConstructor(String.class,int.class);
        intStrCon.setAccessible(true);//忽略訪問限制
        Object inStrObj = intStrCon.newInstance("String",100); //不加會丟擲異常 java.lang.NoSuchMethodException: t201808.t20180831.BeanDemo.<init>(java.lang.String, int)

常用的獲取建構函式方法:

  • getConstructors()獲取所有共有的構造方法 
  • getDeclaredConstructors()獲取所有的構造方法,私有共有,protected 預設
  • 呼叫建構函式就是利用獲得的建構函式物件建立例項

3.通過反射獲取成員變數

        /**二:通過反射拿到成員變數
         *     1.getDeclaredFields()可以拿到所有成員變數
         *     2.getFields() 只能拿到公有的成員變數
         * */
        Field[] NoDecfields = bean.getFields(); //公有成員變數
        Field [] fields = bean.getDeclaredFields();//公有私有都可以拿到
        System.out.println("====================================getFields() 公有成員變數==========================");
        for (Field f  :NoDecfields){
            System.out.println(f);
        }

        System.out.println("====================================getFields() 全部成員變數==========================");
        for (Field f :fields){
            System.out.println(f);
        }
        System.out.println("====================================getFields() 獲取對應公有欄位並呼叫==========================");
        Field pubField = bean.getField("pub");
        //首先要獲取一個pub成員 有值的物件
        Object object = bean.getConstructor(String.class,String.class).newInstance("name","這是我設定的PUB");
        //獲取到該欄位,注意get()方法獲取返回值為物件,還有getInt()等方法可呼叫
        System.out.println(pubField.get(object));
        //設定該成員變數
        pubField.set(object,"新設定的PUB值");
        System.out.println(pubField.get(object));
        //Field的其他方法 getName()可以直接拿到屬性的名字
        System.out.println(pubField.getName());
        //同理私有變數訪問需要setAccessible(true) 忽略許可權

常用的獲取屬性方法:

  • getFields()獲取所有共有的構造方法 
  • getDeclaredFields() 獲取所有的構造方法,私有共有,protected 預設
  • 獲取屬性值的時候,需要2個物件,一個是需要獲取值的物件obj,一個屬性值物件field。
  • 通過呼叫field.get(obj) 可以獲取到物件的對於屬性值。
  • 同樣,若是私有屬性需要setAccessible()

一個fastjson的物件轉字串的例子:

BeanDemo beanObj = new BeanDemo("hhhhh",99);
        Class clazz = beanObj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("{");
       for (Field f : fields){
            Field ageField = clazz.getDeclaredField(f.getName());
            ageField.setAccessible(true);
            System.out.println("\""+f.getName()+"\""+":"+ageField.get(beanObj));
        }
        System.out.println("}");

4.通過反射獲取方法以及呼叫方法

        /**三、通過反射獲取方法以及呼叫方法
         * */
        Method[] pubMethods = bean.getMethods();
        System.out.println("====================================獲取公有方法 包括繼承的方法 實現的==========================");
        for (Method m :pubMethods){
            System.out.println(m);
        }
        System.out.println("==================================== 獲取全部方法,公有私有保護預設,不包括繼承的方法==========================");
        Method[] allMethods = bean.getDeclaredMethods();
        for (Method method : allMethods){
            System.out.println(method);
        }
        System.out.println("====================================獲取指定方法=========================");
        Method method = bean.getMethod("speak1", String.class);//引數列表為 方法名和方法的引數列表型別
        System.out.println(method);
        //呼叫該方法 invoke()
        //需要先建立一個物件
        Object obj = bean.getConstructor().newInstance();
        method.invoke(obj,"?????");//方法的呼叫採用方法物件 呼叫invoke()方法,傳入物件,以及方法需要的引數

        //呼叫有返回值的方法
        method = bean.getDeclaredMethod("speak4", int.class);
        method.setAccessible(true);
        System.out.println(method);
        Object res =method.invoke(obj,12);
        System.out.println(res);

相關推薦

java.lang.reflect反射機制應用

最近也是面試的時候問道一個問題,如何將一個java物件轉換為json字串,一聽到的時候沒有任何思路,之前也有接觸過fastjson,知道就是用這個jar包來處理的,但是具體如何執行原理並不瞭解,導致面試說不出來,面試官提到fastjson其實就是利用反射來獲取這個物件對應的資

java-日誌元件slf4j+logback配置

文字主要介紹一下slf4j+logback在java工程中的配置,面向的讀者是已經對slf4j+logback有一定了解的同學,不瞭解的同學,請看文章末尾的相關連結。以後會寫一篇介紹slf4j框架的文章,其中會說明logback與之的關係。下面咱們進入正題。

Java基礎總結反射

cto 調用構造 lan 調用方法 arm tde ins java 傳遞數據 1. 什麽是反射  Class、Method、Field、Constructor,它們是反射對象。它們是類、方法、成員變量、構造器,在內存中的形式。  也就是萬物皆對象!類是類型、方法是類型、成

Java線程機制:synchronized、Lock、Condition轉載

留下 初始化 char 想要 interrupt 機制 運行 -m 特性 http://www.infoq.com/cn/articles/java-memory-model-5 深入理解Java內存模型(五)——鎖 http://www.ibm.com/develope

Java 字串類的常用方法java.lang.String

public class StringTest {static class sss{String s3="core java";}class sss2{}public static void main(String[] args){String s1="core java"

java.lang.UnsupportedClassVersionError版本不一致出錯

 這種錯誤的全部報錯資訊: 1 java.lang.UnsupportedClassVersionError: org/apache/lucene/store/Directory : Unsupported major.minor version 51.0 2

Java執行緒機制:synchronized、Lock、Condition

http://www.infoq.com/cn/articles/java-memory-model-5  深入理解Java記憶體模型(五)——鎖 http://www.ibm.com/developerworks/cn/java/j-jtp10264/  Java 理論與

JAVA 與 MyCat(5) 類的載入 Java內省/反射機制 註解Annotation

通過mycat來學習java了^^。 上一篇瞭解了XML解析的四種方式,並對MyCat的原始碼進行了修改,這一篇接著往下看: dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile); x

Java面試11常問問題答案(非常詳細)

Java面試常問問題及答案(非常詳細) 一:java基礎 1.簡述string物件,StringBuffer、StringBuilder區分 string是final的,內部用一個final型別的char陣列儲存資料,它的拼接效率比較低,實際上是通過建立一個StringBuffer,讓後臺呼叫a

Mint-UIAction sheet 用法(內含取消事件的觸發方法)

鑑於mint-ui官方文件的極簡描述和對功能介紹的點到為止,許多功能的完全實現是需要通過閱讀原始碼才可以知道其真正的用法。 今天給大家介紹一下Action sheet的用法,以及我踩過的坑,感覺比較有意義,希望能幫到各位。 效果圖: 首先我先帶大家看一下官方的介紹: act

YOLO學習筆記之YOLO配置檔案

在YOLO初體驗中,應用到了一個字尾名為cfg的檔案,在darknet中有一個資料夾,下面有各種各樣的cfg檔案 這些cfg檔案都是YOLO的配置檔案,負責YOLO所需資料集的訓練工作,接下來,給大家詳細講解一下配置檔案。講解配置檔案,我以 yolov2-tiny.

單例深思靜態內部類實現

靜態內部類實現是我個人比較推薦的,其實現如下: publicclass Singleton {     private static class SingletonHolder {         

強文翻譯c++右值引用

原文連結譯註:這篇是我讀過有關右值引用的文章中最通俗易懂的一篇,易懂的同時,其內容也非常全面,所以就翻譯了一下以便加深理解。有翻譯不準的地方請留言指出。INTRODUCTION右值引用是C++11標準中引入的新特性,由於右值引用所解決的問題並不是很直觀,所以很難在一開始就很好

Java.lang包util包等各個包

包名說明java.lang該包提供了Java程式設計的基礎類,例如 Object、Math、String、StringBuffer、System、Thread等,不使用該包就很難編寫Java程式碼了。java.util該包提供了包含集合框架、遺留的集合類、事件模型、日期和時間

Unix 網路程式設計TCP狀態轉換圖

在前面,已經介紹了TCP協議的三路握手和四次揮手。如下圖所示,TCP通訊過程包括三個步驟:建立TCP連線通道(三次握手)、資料傳輸、斷開TCP連線通道(四次揮手)。                  

甘道夫HBase基本資料操作完整版,絕對精品

hbase(main):014:0> describe 'rd_ns:itable' DESCRIPTION                                                                                              

專案實站 php 實現抽獎程式碼上篇 基礎實現

基本思路:使用者生成一個隨機數,和出獎的獎品設定的隨機數比對一下。符合規則則中獎(使用者的隨機數< 獎品設定的概率值),不符則未中獎。 一 專案準備期,需求確認。和產品大哥一陣切磋後,認為需求1.0 //1 抽獎活動有起止時間 //2 獎品有限制個數的大獎,和不限次數的

日常積累-轉maven中scope標籤

scope的分類:1.compile:預設值,表示被依賴專案需要參與當前專案編譯,和後續測試,執行週期也參與其中,是一個比較強的依賴。打包的時候通常需要包含進去。2.test:依賴專案僅僅參與測試相關的工作,包括測試程式碼的編譯和執行,不會被打包,例如:junit3.runt

Java學習筆記 執行緒池使用

有點笨,參考了好幾篇大佬們寫的文章才整理出來的筆記.... 字面意思上解釋,執行緒池就是裝有執行緒的池,我們可以把要執行的多執行緒交給執行緒池來處理,和連線池的概念一樣,通過維護一定數量的執行緒池來達到多個執行緒的複用。 好處 多執行緒產生的問題 一般我們使用到多執行緒的程式設計的時候,需要通過new Thr

JAVA反射機制六(java.lang.reflect包)

instance 檢查 item 類繼承 final win 基類 cte member 一、簡介 java.lang.reflect包提供了用於獲取類和對象的反射信息的類和接口。反射API允許對程序訪問有關加載類的字段,方法和構造函數的信息進行編程訪問。它允許在安全限制