摘要:注解的定義注解通過關(guān)鍵字進(jìn)行定義它的形式跟接口很類似,不過前面多了一個(gè)符號上面的代碼就創(chuàng)建了一個(gè)名字為的注解你可以簡單理解為創(chuàng)建了一張名字為的標(biāo)簽注解的應(yīng)用上面創(chuàng)建了一個(gè)注解那么注解的的使用方法是什么呢創(chuàng)建一個(gè)類然后在類定義的地方加上就可以
java jdk: 10.0.2注解的定義
注解通過 @interface 關(guān)鍵字進(jìn)行定義.
public @interface TestAnnotation { }
它的形式跟接口很類似,不過前面多了一個(gè) @ 符號. 上面的代碼就創(chuàng)建了一個(gè)名字為 TestAnnotaion 的注解.
你可以簡單理解為創(chuàng)建了一張名字為 TestAnnotation 的標(biāo)簽.
注解的應(yīng)用上面創(chuàng)建了一個(gè)注解, 那么注解的的使用方法是什么呢.
@TestAnnotation public class Test { }
創(chuàng)建一個(gè)類 Test, 然后在類定義的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解這個(gè)類了.
你可以簡單理解為將 TestAnnotation 這張標(biāo)簽貼到 Test 這個(gè)類上面.
不過, 要想注解能夠正常工作, 還需要介紹一下一個(gè)新的概念那就是元注解.
元注解元注解是什么意思呢?
元注解是可以注解到注解上的注解, 或者說元注解是一種基本注解, 但是它能夠應(yīng)用到其它的注解上面.
如果難于理解的話, 你可以這樣理解. 元注解也是一張標(biāo)簽, 但是它是一張?zhí)厥獾臉?biāo)簽, 它的作用和目的就是給其他普通的標(biāo)簽進(jìn)行解釋說明的.
元標(biāo)簽有 @Retention、 @Documented、@Target、 @Inherited、 @Repeatable 5 種.
@RetentionRetention 的英文意為保留期的意思. 當(dāng) @Retention 應(yīng)用到一個(gè)注解上的時(shí)候, 它解釋說明了這個(gè)注解的的存活時(shí)間.
它的取值如下:
RetentionPolicy.SOURCE 注解只在源碼階段保留, 在編譯器進(jìn)行編譯時(shí)它將被丟棄忽視.
RetentionPolicy.CLASS 注解只被保留到編譯進(jìn)行的時(shí)候, 它并不會被加載到 JVM 中.
RetentionPolicy.RUNTIME 注解可以保留到程序運(yùn)行的時(shí)候, 它會被加載進(jìn)入到 JVM 中, 所以在程序運(yùn)行時(shí)可以獲取到它們.
我們可以這樣的方式來加深理解, @Retention 去給一張標(biāo)簽解釋的時(shí)候, 它指定了這張標(biāo)簽張貼的時(shí)間.
@Retention 相當(dāng)于給一張標(biāo)簽上面蓋了一張時(shí)間戳, 時(shí)間戳指明了標(biāo)簽張貼的時(shí)間周期.
@Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { }
上面的代碼中, 我們指定 TestAnnotation 可以在程序運(yùn)行周期被獲取到, 因此它的生命周期非常的長.
@Documented顧名思義, 這個(gè)元注解肯定是和文檔有關(guān). 它的作用是能夠?qū)⒆⒔庵械脑匕?Javadoc 中去.
@TargetTarget 是目標(biāo)的意思, @Target 指定了注解運(yùn)用的地方.
你可以這樣理解, 當(dāng)一個(gè)注解被 @Target 注解時(shí), 這個(gè)注解就被限定了運(yùn)用的場景.
ElementType.ANNOTATION_TYPE 可以給一個(gè)注解進(jìn)行注解
ElementType.CONSTRUCTOR 可以給構(gòu)造方法進(jìn)行注解
ElementType.FIELD 可以給屬性(字段)進(jìn)行注解
ElementType.LOCAL_VARIABLE 可以給局部變量進(jìn)行注解
ElementType.METHOD 可以給方法進(jìn)行注解
ElementType.PACKAGE 可以給一個(gè)包進(jìn)行注解
ElementType.PARAMETER 可以給一個(gè)方法內(nèi)的參數(shù)進(jìn)行注解
ElementType.TYPE 可以給一個(gè)類型進(jìn)行注解, 比如類、接口、枚舉
@InheritedInherited 是繼承的意思, 但是它并不是說注解本身可以繼承, 而是說如果一個(gè)超類被 @Inherited 注解過的注解進(jìn)行注解的話, 那么如果它的子類沒有被任何注解應(yīng)用的話, 那么這個(gè)子類就繼承了超類的注解.
說的比較抽象. 代碼來解釋.
@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Test {} @Test public class A {} public class B extends A {}
注解 Test 被 @Inherited 修飾, 之后類 A 被 Test 注解, 類 B 繼承 A, 類 B 也擁有 Test 這個(gè)注解.
@RepeatableRepeatable 自然是可重復(fù)的意思.
什么樣的注解會多次應(yīng)用呢? 通常是注解的值可以同時(shí)取多個(gè).
舉個(gè)例子, 一個(gè)人他既是程序員又是產(chǎn)品經(jīng)理, 同時(shí)他還是個(gè)畫家.
@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person{ String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan{ }
注意上面的代碼, @Repeatable 注解了 Person. 而 @Repeatable 后面括號中的類相當(dāng)于一個(gè)容器注解.
什么是容器注解呢? 就是用來存放其它注解的地方. 它本身也是一個(gè)注解.
我們再看看代碼中的相關(guān)容器注解.
@interface Persons { Person[] value(); }
按照規(guī)定, 它里面必須要有一個(gè) value 的屬性, 屬性類型是一個(gè)被 @Repeatable 注解過的注解數(shù)組, 注意它是數(shù)組.
注解的屬性@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { int id(); String msg(); }
上面代碼定義了 TestAnnotation 這個(gè)注解中擁有 id 和 msg 兩個(gè)屬性. 在使用的時(shí)候, 我們應(yīng)該給它們進(jìn)行賦值.
賦值的方式是在注解的括號內(nèi)以 value=”” 形式, 多個(gè)屬性之前用 , 隔開.
@TestAnnotation(id=3,msg="hello annotation") public class Test { }
?? 在注解中定義屬性時(shí)它的類型必須是 8 種基本數(shù)據(jù)類型外加 類、接口、注解及它們的數(shù)組.判斷類上是否使用指定注解
Map判斷字段上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) ->{ ReflectionClass annotation = value.getAnnotation(ReflectionClass.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 注解 value : " + annotation.Value()); } });
Map判斷方法上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Field declaredField : ClassUtil.getAnnotatedDeclaredFields(value, ReflectionField.class, false)) { ReflectionField annotation = declaredField.getAnnotation(ReflectionField.class); if (annotation != null) { this.put(annotation.Value(), declaredField); System.out.println("class name: " + value.getSimpleName() + ", 字段名: " + declaredField.getName() + ", 字段類型:" + declaredField.getType().getSimpleName() + ", 注解值:" + annotation.Value() ); } } });
Map創(chuàng)建對象> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Method declaredField : ClassUtil.getAnnotatedDeclaredMethods(value, ReflectionMethod.class,false)) { ReflectionMethod annotation = declaredField.getAnnotation(ReflectionMethod.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 方法名: " + declaredField.getName() + ", 方法返回類型:" + declaredField.getReturnType() + ", 注解值:" + annotation.id() ); } } });
value.getConstructor().newInstance();
上面代碼是使用無參構(gòu)造來創(chuàng)建對象, 當(dāng)然也可以使用有參構(gòu)造來創(chuàng)建對象.
getConstructor() 參數(shù)填寫構(gòu)造參數(shù)的參數(shù)類型.
newInstance() 參數(shù)填寫傳給構(gòu)造參數(shù)的值.
調(diào)用方法可以通過 Method 的 setAccessible 方法設(shè)置為 true, 就可以調(diào)用對象的 private 方法.
declaredField.setAccessible(true); declaredField.invoke(value);
然后可以使用 invoke 方法來進(jìn)行方法調(diào)用. 第一個(gè)參數(shù)為要調(diào)用方法的對象. 剩下的參數(shù)是方法參數(shù).
總結(jié)如果想實(shí)現(xiàn)像 Spring 這種框架, 實(shí)現(xiàn)上面幾步是必須.
比如依賴注入, 我們需要知道字段的類型, 然后到 IOC 容器中找到對應(yīng)的對象進(jìn)行賦值.
而方法調(diào)用你可以先將注解的方法進(jìn)行保存, 比如保存到 Map 集合中.
例如客戶端發(fā)送指定數(shù)據(jù)幀后, 然后通過 key 取出要執(zhí)行的方法后執(zhí)行就可以.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/72326.html
摘要:反射機(jī)制一結(jié)合官方通過編寫的反射教程,復(fù)習(xí)一下反射的知識。反射的概念反射是一種在運(yùn)行時(shí)獲取以及修改應(yīng)用行為的一種工具。因?yàn)榉瓷湫枰獎(jiǎng)討B(tài)的解析類的信息,相比于非反射使用的方式要慢。反射需要獲取一定的運(yùn)行時(shí)權(quán)限,在特定的安全環(huán)境下不一定存在。 Java反射機(jī)制(一) 結(jié)合Oracle官方通過JDK8編寫的反射教程,復(fù)習(xí)一下反射的知識。結(jié)尾篇補(bǔ)一個(gè)小例子。 主要內(nèi)容 這次博客的主要內(nèi)容就是簡...
摘要:反射非常強(qiáng)大和有用。另外,反射可以用在映射結(jié)果集的列名到對象的方法。本教程將深入介紹反射。本教程還將清除一些關(guān)于范型信息在運(yùn)行時(shí)可用性的認(rèn)知混淆。類對象使用反射時(shí),起點(diǎn)通常是需要使用反射檢視的類的對象。 Java反射可以在運(yùn)行時(shí)檢視類、接口、屬性和方法,而無需在編譯時(shí)知道類名、方法名等等。它也同樣使用反射支持實(shí)例化新的對象、調(diào)用方法和get/set屬性值。 Java反射非常強(qiáng)大和有用...
摘要:通過反射獲取帶參無返回值成員方法并使用設(shè)置安全檢查,訪問私有構(gòu)造函數(shù)必須創(chuàng)建實(shí)例這種不行,注意和方法需要傳遞參數(shù)測試復(fù)制這個(gè)功能獲取私有方法,同樣注意和的區(qū)別賦予訪問權(quán)限調(diào)用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...
摘要:反射使用類對象提供的基本元數(shù)據(jù),能從類對象中找出方法或字段的名稱,然后獲取表示方法或字段的對象。常見的反射手段有反射和反射。以之前的反射為例其中指定了方法的返回類型,其實(shí)不止如此。 Java反射機(jī)制主要提供了以下功能: 在運(yùn)行時(shí)判斷任意一個(gè)對象所屬的類 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對象 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法 在運(yùn)行時(shí)調(diào)用任意一個(gè)對象的方法 生成動(dòng)態(tài)代理 很多框架...
近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對反射進(jìn)行分析: 反射的優(yōu)勢和劣勢 反射的應(yīng)用場景 反射的優(yōu)勢和劣勢 ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...
摘要:一反射機(jī)制概念程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如,是動(dòng)態(tài)語言顯然,,不是動(dòng)態(tài)語言,但是有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制。相關(guān)的為二獲取源頭重點(diǎn)打開權(quán)限所有類的對象其實(shí)都是的實(shí)例。 一、Java反射機(jī)制概念 程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動(dòng)態(tài)語言,如Python, Ruby是動(dòng)態(tài)語言;顯然C++,Java,C#不是動(dòng)態(tài)語言,但是JAVA有...
閱讀 1834·2021-11-24 09:39
閱讀 1631·2021-11-16 11:54
閱讀 3586·2021-11-11 16:55
閱讀 1823·2021-10-14 09:43
閱讀 1506·2019-08-30 15:55
閱讀 1295·2019-08-30 15:54
閱讀 3482·2019-08-30 15:53
閱讀 1432·2019-08-30 14:18