深入理解java注解,java的4个元注解,注解三要素——定义、使用及读取执行,深入了解注解的底层本质,通过反射自动、动态获取注解所有属性以及属性值
1. 注解的定義
注解也是一種引用類型,編譯后會生成 .class 字節(jié)碼文件,作用就是為程序進(jìn)行標(biāo)識,不同注解能實(shí)現(xiàn)不同功能。
2. 注解的使用
3. 注解的讀取執(zhí)行
3.1 得不到注解信息,得到的是null
3.2 在MyAnnotation1注解 加上?@Retention(RetentionPolicy.RUNTIME) 以及 MyAnnotation3注解 加上?@Retention(RetentionPolicy.CLASS)后,得到了MyAnnotation1注解信息,但沒得到MyAnnotation3注解信息,如下圖。
?
4. java中的4個元注解:@Documented、@Inherited、@Retention和@Target
4.1 @Documented注解使用后會被javadoc工具處理,內(nèi)部沒有屬性,@Documented注解源代碼如下圖。
4.2?@Inherited注解:包含@Inherited的注解會被子類繼承;@Inherited注解只能在類使用,不能用于方法、屬性等;查詢某個類是否使用了包含@Inherited的注解時,不僅會查詢當(dāng)前類,還會在父類中查詢,直至到達(dá)Object類。@Inherited注解源代碼及使用如下圖。
4.3?@Target注解:指定注解被用于什么位置,是用在類上還是方法上或是屬性等等,由ElementType數(shù)組指定,可指定的位置主要有10種,@Target注解源代碼及ElementType取值范圍及@Target注解使用如下圖所示。
4.4 @Retention注解:表示注解保存到什么時候。@Retention注解源代碼及RetentionPolicy取值范圍如下圖所示,@Retention注解的使用在3.2中已經(jīng)分析過。
5. 深入了解注解的本質(zhì)及動態(tài)獲取注解屬性值
5.1 我們以MyAnnotation2和MyAnnotation3注解為例,代碼如下。
@Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{int age();String name();int[] hobby(); }@Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{String value(); }5.2 然后使用注解的測試類AnnotationTest代碼如下。
5.3 讀取注解并執(zhí)行,代碼如下。
5.4 到這里,我們是不是算完成注解的定義、使用及讀取了呢?其實(shí)這邊還有兩個問題:1.為什么注解中的屬性獲取和執(zhí)行方法形式一致?2.我們可不可以動態(tài)、自動地獲取注解的所有屬性及屬性值呢?
5.5 我們先加載注解MyAnnotation2,并查看一下注解的信息,如下圖。
同時查看一下字節(jié)碼的反編譯代碼,雖然注解的形式和接口幾乎一致,但是有一個操作我們很費(fèi)解,就是可以給注解里的屬性賦值,我們剛說完注解的屬性實(shí)際是方法,那么方法怎么能賦值呢?所以這里有個奇怪的點(diǎn),所以我們還是要特別對待注解和接口。
5.6 既然注解中的屬性實(shí)際上是方法,那么想通過反射獲取屬性值,是不是也是通過方法反射,而不是屬性反射呢?結(jié)果如下圖。
5.7? 通過5.5和5.6,我們解決了兩個問題:為什么注解中的屬性和方法一樣的形式;怎么能夠通過反射自動、動態(tài)地獲取注解所有屬性及屬性值。
附錄:代碼和最終運(yùn)行結(jié)果
import java.lang.annotation.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays;@MyAnnotation3("class_annotation") public class AnnotationTest{@MyAnnotation3("mem_annotation")private String mem;public static void main(String[] args) throws Exception {// 通過反射得到AnnotationTest類Class<?> annotationTest = Class.forName("AnnotationTest");// 獲取AnnotationTest類使用的MyAnnotation3注解MyAnnotation3 annotation = annotationTest.getAnnotation(MyAnnotation3.class);System.out.println("獲取類AnnotationTest使用的MyAnnotation3注解信息:" + annotation);// 通過反射,動態(tài)獲取AnnotationTest類的所有屬性// 這里要注意getDeclaredFields方法是得到當(dāng)前類所有聲明的方法,不管訪問權(quán)限,但不包含父類的方法// getFields方法則是得到訪問權(quán)限是public的方法,包含父類的公共方法。Field[] declaredFields = annotationTest.getDeclaredFields();for(Field f: declaredFields){// 獲取屬性使用的MyAnnotation3注解信息MyAnnotation3 annotation1 = f.getAnnotation(MyAnnotation3.class);if(annotation1 != null){System.out.println("獲取屬性mem使用的MyAnnotation3注解的value屬性值:" + annotation1.value());}}// 與上面類似Method[] declaredMethods = annotationTest.getDeclaredMethods();Class<?> myAnnotation2 = Class.forName("MyAnnotation2");for(Method m: declaredMethods){MyAnnotation2 annotation1 = m.getAnnotation(MyAnnotation2.class);if(annotation1 != null){// 通過反射自動、動態(tài)地獲取注解的屬性及屬性值System.out.print("通過反射獲取MyAnnotation2注解的屬性及屬性值, ");Method[] declaredMethods2 = myAnnotation2.getDeclaredMethods();for(Method mm: declaredMethods2){if(mm.getName().equals("hobby")){System.out.print(mm.getName() + ":" + Arrays.toString((int[])mm.invoke(annotation1)) + " ");}else{System.out.print(mm.getName() + ":" + mm.invoke(annotation1) + " ");}}System.out.println();}MyAnnotation3 annotation2 = m.getAnnotation(MyAnnotation3.class);if(annotation2 != null){System.out.println("獲取方法" + m.getName() + "使用的MyAnnotation3注解信息: " + annotation2.value());}}}@MyAnnotation3("test1")static void test1(){}@MyAnnotation2(name = "lhj", age = 15, hobby = {1,3})static void test2(){} }@Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{int age();String name();int[] hobby(); }@Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{String value(); }總結(jié)
以上是生活随笔為你收集整理的深入理解java注解,java的4个元注解,注解三要素——定义、使用及读取执行,深入了解注解的底层本质,通过反射自动、动态获取注解所有属性以及属性值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java浅克隆与深克隆区别详解与实现,以
- 下一篇: 轻轻松松明白什么是反射,反射有什么用,简