開發筆記之你弄不懂的JAVA反射機制

FrigidCrow發表於2017-03-15

_寒鴉, FrigidCrow
我熱愛程式設計, 程式碼讓我快樂, 我認為上帝就是最強大的程式設計師, "Hello World"真正的開闢了一個世界.


JAVA反射機制, 嘖嘖, 當你看到這幾個字的時候就有一種不好的預感, 沒錯, 這個東西是不怎麼好理解, 所以特開此篇, 從實用的角度, 用確切的程式碼來講解一下"反射"這個東西.


開啟X度, X度百科上面寫著:

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制.

你懵逼了, 覺得這簡直都不是人話, 讓我這個萌新程式設計師怎麼愉快的玩耍.

######所以, 先拋棄概念, 拋棄定義, 先從JAVA中關於反射的方法和程式碼去入手.

首先, JAVA的反射你一定要知道四個類:

Class,Constructor,Field,Method;
Class 代表類的物件
Constructor 代表類的構造器物件
Field 代表了類的成員變數
Method 代表了類的方法物件

你猛然一抖, 覺得這個東西完全可以構造出一個類, 你應該獎勵你自己再抖兩下(斜眼笑).

然後, 跟著我, 一步一步走, 教你怎麼用出反射這個技能.

開發筆記之你弄不懂的JAVA反射機制
新建一個Person類

然後讓我們看一個Class的方法

static Class<?> forName(String className)
// 返回的是與帶有給定字串名的類或介面相關聯的 Class 物件複製程式碼

既然讓你給定一個關於類的String型別的引數那就給咯
那還知不知道一個類的全稱是啥了? ------ 包+類名

// Class 代表類的物件
Class clazz = Class.forName("com.company.Person");複製程式碼

你已經抓住這個類了 ! 讓我們好好玩玩他 !
你的魔掌現在伸向了構造器 ------ 而JAVA提供了一個Constructor來讓你爽.

// Constructor 代表類的構造器物件
Constructor constructor = clazz.getConstructor(String.class, int.class);複製程式碼

仔細的看這段程式碼, 一瞬間感到程式設計的美感.
你不但拿到了構造器, 而且你關聯了你上面拿到的類(clazz), 而且你也確定了引數的型別. 是不是?
下面的程式碼很重要, 劃重點 ! (拍).

 T newInstance()
//  建立此 Class 物件所表示的類的一個新例項複製程式碼
Object object = constructor.newInstance("hehe", 11);複製程式碼

你連帶著把值都通過構造器付給了例項物件, 下一步, 獲取方法 !

獲取方法

// Method 代表了類的方法物件
Method fooMethod = clazz.getMethod("foo", String.class);複製程式碼

方法呼叫

fooMethod.invoke(object, "haha");複製程式碼

你通過你拿到的類(clazz)關聯到了屬於他的foo方法, 並且確定了引數的型別, 付給了方法物件fooMethod. 呼叫時, 你通過方法物件fooMethod, 就能去"啟用"屬於object物件的foo方法, 而且你付給了他引數, 達到了"啟用"的條件.

無參的方法怎麼辦?

Method sayMethod = clazz.getMethod("say");
sayMethod.invoke(null);複製程式碼

同樣是這個套路.

下一步就到了反射最重要, 也是最好玩的地方了, 我們拿成員變數.

Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(object, "Du Xiandong");
System.out.println(field.get(object));複製程式碼

讓我們看一下結果:

開發筆記之你弄不懂的JAVA反射機制
列印臺結果

你覺得好像有什麼不對, 然後你回頭看了一眼Person.

開發筆記之你弄不懂的JAVA反射機制
注意name的許可權

開發筆記之你弄不懂的JAVA反射機制
說好的私有呢?

在程式設計裡說好的私有都是騙人的(斜眼笑), 而這就是反射裡一個非常重要的機制, 他可以強行獲取私有成員變數, 忽略欄位的訪問許可權檢查, 這裡面能做的文章可就多了.
而這就歸功於這個方法.

field.setAccessible(true);複製程式碼

你現在是不是知道反射應該怎麼用了呢? 但是你還是疑惑, 除了這個強行獲取私有成員變數之外, 還有什麼用處, 還能怎麼用呢?


下面就讓我們拿一個例子來解決這個問題.
首先, 我們知道客戶端, 伺服器這個東西, 伺服器要處理來自客戶端的請求, 然後去返回資料, 我們就模擬這個過程, 來看一下反射.
來讓我們做一下準備工作:
建立兩個類, 一個介面, 一個file檔案

開發筆記之你弄不懂的JAVA反射機制
注意名稱, 字尾名和層級關係

在介面中寫上

public String handleRequest(String string);複製程式碼

然後兩個類去實現這個介面.

// 注意兩個類的列印要有點分別, 否則不好分辨
    @Override
    public String handleRequest(String string) {
        System.out.println("收到請求:" + string);
        return "結果"+string;
    }複製程式碼

去file檔案, 貼上下面的兩行程式碼

javarise.com/home=com.company.HomeRequestHandler
javarise.com/mine=com.company.MineRequestHandler複製程式碼

OK, 到這裡, 準備工作完畢 ! 讓我們開始模擬這個過程吧.
回到Main

String[] requesUrlArr = {"javarise.com/home", "javarise.com/mine"};
File configFile = new File("src/MyConfig.properties");
Properties configProperties = new Properties();
FileInputStream fileInputStream = new FileInputStream(configFile);
configProperties.load(fileInputStream);
System.out.println(configProperties);複製程式碼

如程式碼可見, 我模擬了兩個請求, 並且關聯到了MyConfig.properties這個file檔案, 通過file中的那兩行程式碼, 我們就相當於獲取到了HomeRequestHandler和MineRequestHandler
然後懷揣著你的疑問, 不要糾結, 繼續往下看

     for (String url :
                requesUrlArr) {
            // 從properties中根據key獲取value取出的value就是我們想要的類名, 處理對應請求的類名
            String className = configProperties.getProperty(url);

            // 反射 根據類名生成對應的類
            Class clazz = Class.forName(className);
            // 根據類生成對應的例項
            RequestHandleInterface requestHandle = (RequestHandleInterface) clazz.newInstance();
            String request = requestHandle.handleRequest(url);
            System.out.println(request);
        }複製程式碼

用心看註釋, 你瞭解到了什麼? 反射的能力, 強大的解耦性, 新種類的請求只需要在file檔案裡面新增新的請求=類, 然後建好這個類, 實現這個介面就好了, 怎麼樣, 程式碼十分靈活, 強大的解耦, 你是不是覺得反射這個東西很強大? 回過頭, 看看反射的定義.

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制.

是不是懂了反射的意思和功能? 當然了, 反射的能力絕對不止這一點, 但是, 路已經開拓了, 剩下的你只需要走下去就好了.


我們作為程式設計師, 每天都在想的無非就是我怎麼把程式碼敲得更牛逼, 更美觀, 而我一直認為知識, 見解, 經驗的分享和學習是自我進行學習的一個重要的途徑, 所以, 知識的分享總會增值, 非常期待與各位看官切磋想法, 交流心得.

個人其他文章:
個人程式設計想法心得(不定期更新)
開發筆記之詳述JAVA建構函式和程式碼塊本身及其執行細節
開發筆記之氣泡排序, 選擇排序, 折半查詢
iOS開發筆記-基於AFNetworking 3.0的登入 註冊
開發筆記之JAVA String StringBuffer StringBuilder
開發筆記之JAVA ArrayList 和 LinkedList

相關文章