七分鐘理解 Java 的反射 API
像java一樣,一種具有反射功能的語言。允許開發人員在執行時檢查型別、方法、欄位、註解等,並在程式執行時決定是否使用。 為此,Java的反射API提供類,類,欄位,建構函式,方法,註釋和其他。 使用它們可以與編譯時未知的型別進行互動,例如建立未知類的例項並對它們呼叫方法。
這個快速提示旨在讓您深度瞭解什麼是反射,它在Java中的使用,以及它可以用於什麼。 之後,你將準備好開始或工作更長的教程。 為了充分使用它,你應該很好地理解Java的類構造器,特別是什麼類和方法以及它們如何關聯。 瞭解註釋可解鎖單獨的部分。
Reflection API
我們從一個簡單的Java程式碼開始(程式碼針對有一定java基礎的閱讀人員)
URL url = new URL("https://sitepoint.com/java "); String urlString = url.toExternalForm(); System.out.println(urlString);
我決定在編譯時(即當我在寫程式碼時)建立一個URL物件,並且呼叫了其中的一些方法。下面演示了我使用Java的反射API完成了同樣的事情:
// the gateway to reflection is the `Class` instance // for the class you want to operate on Class type = Class.forName("java.net.URL"); // fetches the constructor that takes a `String` argument // and uses it to create a new instance for the given string Constructor constructor = type.getConstructor(String.class); Object instance = constructor.newInstance("https://sitepoint.com/java"); // fetches the `toExternalForm` method and invokes it on // the instance that was just created Method method = type.getMethod("toExternalForm"); Object methodCallResult = method.invoke(instance); System.out.println(methodCallResult);
使用反射API的確比直接寫程式碼要笨重一點. 但是使用反射你會發現, 你在程式碼當中的呼叫細節 (比如說我用的URL這個類以及我呼叫其中的方法) 變成了僅僅一個引數. 結果呢,在編譯期間URL以及toExternalForm並沒有繫結, 它們是在程式開始執行的時候才被決定繫結的
反射的大多數用例都是“框架”的場景下 ,想想junit, 比如說, 執行所有被@ test註解的方法. 一旦框架在classpath掃描的時候找到註解它就會呼叫getMethod以及invoke函式去執行使用者程式碼. spring和其他的一些web框架在搜尋控制器以及url對映的收也差不多是這麼做的,對可擴充套件的應用程式來說反射的另外一個用途就是在執行時載入使用者提供的外掛
基本型別和方法
呼叫反射API的方法是Class :: forName。 在它的簡單形式中,這個靜態方法只需要一個完全限定的類名,併為它返回一個Class例項。 該例項可用於獲取欄位,方法,建構函式等。
通過構造器函式獲取類物件,getConstructor方法可以使用建構函式引數的型別呼叫,就像我上面做的那樣。 類似地,可以通過呼叫getMethod並傳遞其名稱以及引數型別來訪問特定方法。 上面的getMethod(“toExternalForm”)呼叫沒有指定任何型別,因為該方法沒有引數。
這裡有一個方法:
Class type = Class.forName("java.net.URL "); // `URL::openConnection` has an overload that accepts a java.net.Proxy Method openConnection = type.getMethod("openConnection ", Proxy.class);
這些呼叫返回的例項分別是Constructor和Method型別。 要呼叫底層成員,他們提供類似於Constructor :: newInstance和Method :: invoke的方法。 後者的一個有趣的細節是,要呼叫該方法的例項需要作為第一個引數傳遞給它(它指類的例項)。 其他引數將被傳遞給被呼叫的方法。
繼續openConnection示例:
openConnection.invoke(instance, someProxy);
如果要呼叫靜態方法,則將忽略例項引數,因此可以為null。
註解
註解是反射的重要組成部分。 事實上,註解主要針對反射。 它們旨在提供程式執行時訪問的元資訊,然後用於塑造程式的行為。 (如上所述,JUnit的@Test和Spring的@Controller和@RequestMapping是很好的例子。)
所有重要的反射相關型別,如類,欄位,建構函式,方法和引數實現AnnotatedElement介面。 連結的Javadoc包含了註釋如何與這些元素(直接呈現,間接呈現或關聯)相關的詳細解釋,但是它最簡單的形式是:getAnnotations方法以註釋例項陣列的形式返回該元素上存在的註釋 ,然後可以訪問其成員。
寫在最後:歡迎留言討論,加關注,持續更新!