漫反射 高光反射_如何有效地使用反射
漫反射 高光反射
本文是我們名為“ 高級Java ”的學院課程的一部分。
本課程旨在幫助您最有效地使用Java。 它討論了高級主題,包括對象創建,并發,序列化,反射等。 它將指導您完成Java掌握的旅程! 在這里查看 !
目錄
1.簡介 2.反射API 3.訪問泛型類型參數 4.反射API和可見性 5.反射API陷阱 6.方法句柄 7.方法參數名稱 8.接下來 9.下載源代碼1.簡介
在本教程的這一部分中,我們將簡要介紹一個非常有趣的主題,即反射 。 反射是程序在運行時檢查或自檢的能力。 反射是一項非常有用且功能強大的功能,它可以極大地擴展程序的功能,以在執行過程中執行其自己的檢查,修改或轉換,而無需一行代碼更改。 并非每種編程語言實現都支持此功能,但是幸運的是Java自一開始就采用了此功能。
2.反射API
反射API是Java標準庫的一部分,它提供了一種在運行時探索內部類詳細信息,動態創建新類實例(無需顯式使用new運算符),動態調用方法,自省注釋(已添加注釋)的方法。在教程的第5部分“ 如何以及何時使用Enums和Annotations”中進行了介紹 ,以及更多其他內容。 它使Java開發人員可以自由編寫代碼,這些代碼可以在運行時自行調整,驗證,執行甚至修改自己。
Reflection API以非常直觀的方式設計,并托管在java.lang.reflect包下。 它的結構嚴格遵循Java語言概念,并具有表示類(包括通用版本),方法,字段(成員),構造函數,接口,參數和注釋的所有元素。 Reflection API的入口點是Class< ? > Class< ? >類。 例如,列出String類的所有公共方法的最簡單方法是使用getMethods()方法調用:
final Method[] methods = String.class.getMethods(); for( final Method method: methods ) {System.out.println( method.getName() ); }按照相同的原則,我們可以使用getFields()方法調用列出String類的所有公共字段,例如:
final Field[] fields = String.class.getFields(); for( final Field field: fields ) {System.out.println( field.getName() ); }繼續使用反射類對String類進行實驗,讓我們嘗試創建一個新實例,并在其上調用length()方法,所有這些僅通過使用反射API即可 。
final Constructor< String > constructor = String.class.getConstructor( String.class ); final String str = constructor.newInstance( "sample string" ); final Method method = String.class.getMethod( "length" ); final int length = ( int )method.invoke( str ); // The length of the string is 13 characters可能最需要反射的用例圍繞注釋處理。 注釋本身(不包括Java標準庫中的注釋)對代碼沒有任何影響。 但是,Java應用程序可以使用反射在運行時檢查它們感興趣的不同Java元素上存在的注釋,并根據注釋及其屬性應用某些邏輯。 例如,讓我們看一下自省的方式是否存在于類定義中:
@Retention( RetentionPolicy.RUNTIME ) @Target( ElementType.TYPE ) public @interface ExampleAnnotation {// Some attributes here }@ExampleAnnotation public class ExampleClass {// Some getter and setters here }使用反射API ,可以使用getAnnotation()方法調用輕松完成。 返回的非null值表示存在注釋,例如:
final ExampleAnnotation annotation =ExampleClass.class.getAnnotation( ExampleAnnotation.class );if( annotation != null ) {// Some implementation here }如今,大多數Java API都包含注釋,以方便開發人員使用和集成它們。 非常流行的Java規范的最新版本,例如RESTful Web服務的Java API ( https://jcp.org/en/jsr/detail?id=339 ), Bean驗證 ( https://jcp.org/en/jsr / detail?id = 349 ), Java臨時緩存API ( https://jcp.org/en/jsr/detail?id=107 ), Java消息服務 ( https://jcp.org/en/jsr/detail? id = 343 ), Java Persistence ( https://jcp.org/en/jsr/detail?id=338 )以及許多其他構建在注釋之上,它們的實現通常大量使用Reflection API來收集有關正在運行的應用程序。
3.訪問泛型類型參數
自從引入泛型(本教程的第4部分“ 如何和何時使用泛型”介紹了泛型 )以來, Reflection API已得到擴展,以支持對泛型類型的自省。 在許多不同的應用程序中經常彈出的用例是弄清楚用其聲明了特定類,方法或其他元素的通用參數的類型。 讓我們看一下示例類聲明:
public class ParameterizedTypeExample {private List< String > strings;public List< String > getStrings() {return strings;} }現在,在使用Reflection檢查類時,很容易知道將strings屬性聲明為具有String類型參數的泛型類型List 。 下面的代碼段說明了如何實現:
final Type type = ParameterizedTypeExample.class.getDeclaredField( "strings" ).getGenericType();if( type instanceof ParameterizedType ) {final ParameterizedType parameterizedType = ( ParameterizedType )type;for( final Type typeArgument: parameterizedType.getActualTypeArguments() ) {System.out.println( typeArgument );} }以下通用類型參數將被打印在控制臺上:
class java.lang.String4.反射API和可見性
在本教程的第1部分“ 如何創建和銷毀對象”中 ,我們第一次遇到了Java語言支持的可訪問性和可見性規則。 可能令人驚訝,但是反射API能夠以某種方式修改給定類成員的可見性規則。
讓我們看一下帶有單個私有字段名稱的類的以下示例。 提供了此字段的getter,但沒有提供setter,這是有意為之。
public static class PrivateFields {private String name;public String getName() {return name;} }顯然,對于任何Java開發人員而言,顯然都無法使用Java語言語法構造來設置name字段,因為該類無法提供實現此目的的方法。 關于救援的反射API ,讓我們看看如何通過更改字段的可見性和可訪問范圍來完成。
final PrivateFields instance = new PrivateFields(); final Field field = PrivateFields.class.getDeclaredField( "name" ); field.setAccessible( true ); field.set( instance, "sample name" ); System.out.println( instance.getName() );以下輸出將打印在控制臺上:
sample name請注意,如果沒有field.setAccessible( true )調用,則會在運行時引發異常,表明無法訪問帶有修飾符private的類的成員。
反射API的此功能經常由測試支架或依賴項注入框架使用,以便訪問內部(或不可暴露)的實現細節。 除非您別無選擇,否則請嘗試避免在應用程序中使用它。
5.反射API陷阱
另外,請注意,即使反射API非常強大,也有一些陷阱。 首先,它是安全權限的主題,可能并非在您的代碼正在其上運行的所有環境中都可用。 其次,它可能會對您的應用程序性能產生影響。 從執行前景來看,對反射API的調用非常昂貴。
最后, 反射API不能提供足夠的類型安全保證,迫使開發人員在大多數地方使用Object實例,并且在轉換構造函數/方法參數或方法返回值方面受到很大限制。
自Java 7發行以來,有一些有用的功能可以提供更快,另一種方法來訪問某些功能,這些功能以前只能通過反射調用來使用。 下一節將向您介紹它們。
6.方法句柄
Java 7版本向JVM和Java標準庫(方法句柄)引入了一個非常重要的新功能。 方法句柄是對基礎方法,構造函數或字段(或類似的低級操作)的類型化,直接可執行的引用,具有自變量或返回值的可選轉換。 在許多方面,它們是使用Reflection API執行的方法調用的更好替代方法。 讓我們看一下使用方法句柄動態調用String類上的方法length()的代碼片段。
final MethodHandles.Lookup lookup = MethodHandles.lookup(); final MethodType methodType = MethodType.methodType( int.class ); final MethodHandle methodHandle =lookup.findVirtual( String.class, "length", methodType ); final int length = ( int )methodHandle.invokeExact( "sample string" ); // The length of the string is 13 characters上面的示例不是很復雜,只是概述了方法處理能力的基本概念。 請將其與使用“ 反射API ”部分中的“ 反射API”的相同實現進行比較。 但是,它看起來確實有些冗長,但是從性能和類型安全性角度來看,預期的方法句柄是更好的選擇。
方法句柄是非常強??大的工具,它們為在JVM平臺上有效實現動態(和腳本)語言奠定了必要的基礎。 在本教程的第12部分 , 動態語言支持中 ,我們將介紹其中的幾種語言。
7.方法參數名稱
Java開發人員多年來面臨的一個眾所周知的問題是,方法參數名稱沒有在運行時保留,而是被徹底清除。 幾個社區項目,例如Paranamer ( https://github.com/paul-hammant/paranamer ),試圖通過向生成的字節碼中注入一些其他元數據來解決此問題。 幸運的是,Java 8通過引入新的編譯器參數–parameters改變了這一點,該–parameters將確切的方法參數名稱注入字節碼中。 讓我們看一下以下方法:
public static void performAction( final String action, final Runnable callback ) {// Some implementation here }在下一步中,讓我們使用Reflection API檢查該方法的方法參數名稱,并確保保留它們:
final Method method = MethodParameterNamesExample.class.getDeclaredMethod( "performAction", String.class, Runnable.class ); Arrays.stream( method.getParameters() ).forEach( p -> System.out.println( p.getName() ) );指定了-parameters編譯器選項后,以下參數名稱將打印在控制臺上:
action callback對于許多Java庫和框架的開發人員來說,這一期待已久的功能確實使他們大為欣慰。 從現在開始,僅使用純Java Reflection API即可提取更多有用的元數據,而無需引入任何其他變通方法(或黑客手段)。
8.接下來
在本教程的這一部分中,我們介紹了反射API ,它是檢查代碼,從代碼中提取有用的元數據甚至進行修改的方法。 盡管存在所有缺點,但反射API如今已在大多數(如果不是全部)Java應用程序中得到了廣泛使用。 在本教程的下一部分中,我們將討論Java中的腳本和動態語言支持。
9.下載源代碼
這是高級Java課程的第11部分“ 反射” 課程 。 您可以在此處下載源代碼: advanced-java-part-11
翻譯自: https://www.javacodegeeks.com/2015/09/how-to-use-reflection-effectively.html
漫反射 高光反射
總結
以上是生活随笔為你收集整理的漫反射 高光反射_如何有效地使用反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最新ddos网页端源码(ddos源码对接
- 下一篇: junit测试找不到数据库_将数据库日志