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