1. 程式人生 > >基礎篇:深入解析JAVA註解機制

基礎篇:深入解析JAVA註解機制

[TOC](目錄標題) # java實現註解的底層原理和概念 - java註解是JDK1.5引入的一種註釋機制,java語言的類、方法、變數、引數和包都可以被註解標註。和Javadoc不同,java註解可以通過反射獲取標註內容 - 在編譯器生成.class檔案時,註解可以被嵌入位元組碼中,而jvm也可以保留註解的內容,在執行時獲取註解標註的內容資訊 - java提供的註解可以分成兩類:
**作用在程式碼上的功能註解(部分)**: 註解名稱 | 功能描述 --- | --- @Override | 檢查該方法是否是重寫方法。如果發現其父類,或者是引用的介面中並沒有該方法時,會報編譯錯誤 @Deprecated | 標記過時方法。如果使用該方法,會報編譯警告 @SuppressWarnings | 指示編譯器去忽略註釋解中宣告的警告 @FunctionalInterface | java8支援,標識一個匿名函式或函式式介面
**讓給程式設計師開發自定義註解的元註解(和關鍵字@interface配合使用的註解)** 元註解名稱 | 功能描述 --- | --- @Retention | 標識這個註釋解怎麼儲存,是隻在程式碼中,還是編入類檔案中,或者是在執行時可以通過反射訪問 @Documented | 標識這些註解是否包含在使用者文件中 @Target | 標識這個註解的作用範圍 @Inherited | 標識註解可被繼承類獲取 @Repeatable | 標識某註解可以在同一個宣告上使用多次 - Annotation是所有註解類的共同介面,不用顯示實現。註解類使用@interface定義(代表它實現Annotation介面),搭配元註解使用,如下 ```java package java.lang.annotation; public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); // 返回定義的註解型別,你在程式碼宣告的@XXX,相當於該型別的一例項 Class annotationType(); } -----自定義示例----- @Retention( value = RetentionPolicy.RUNTIME) @Target(value = ElementType.TYPE) public @interface ATest { String hello() default "siting"; } ``` ATest的位元組碼檔案,編譯器讓自定義註解實現了Annotation介面 ```java public abstract @interface com/ATest implements java/lang/annotation/Annotation { // compiled from: ATest.java @Ljava/lang/annotation/Retention;(value=Ljava/lang/annotation/RetentionPolicy;.RUNTIME) @Ljava/lang/annotation/Target;(value={Ljava/lang/annotation/ElementType;.TYPE}) // access flags 0x401 public abstract hello()Ljava/lang/String; default="siting" } ``` - 自定義註解型別時,一般需要用@Retention指定註解保留範圍RetentionPolicy,@Target指定使用範圍ElementType。RetentionPolicy保留範圍只能指定一個,ElementType使用範圍可以指定多個 - 註解資訊怎麼和程式碼關聯在一起,java所有事物都是類,註解也不例外,加入程式碼`System.setProperty("sum.misc.ProxyGenerator.saveGeneratedFiles","true");` 可生成註解相應的代理類 ![](https://img-blog.csdnimg.cn/img_convert/463987e541aefabceda1dd3d8c9aa21a.png) 在程式碼裡定義的註解,會被jvm利用反射技術生成一個代理類,然後和被註釋的程式碼(類,方法,屬性等)關聯起來 # 五種元註解詳解 - @Retention:指定註解資訊保留階段,有如下三種列舉選擇。只能選其一 ```java public enum RetentionPolicy { /** 註解將被編譯器丟棄,生成的class不包含註解資訊 */ SOURCE, /** 註解在class檔案中可用,但會被JVM丟棄;當註解未定義Retention值時,預設值是CLASS */ CLASS, /** 註解資訊在執行期(JVM)保留(.class也有),可以通過反射機制讀取註解的資訊, * 操作方法看AnnotatedElement(所有被註釋類的父類) */ RUNTIME } ``` - @Documented:作用是告訴JavaDoc工具,當前註解本身也要顯示在Java Doc中(不常用) - @Target:指定註解作用範圍,可指定多個 ```java public enum ElementType { /** 適用範圍:類、介面、註解型別,列舉型別enum */ TYPE, /** 作用於類屬性 (includes enum constants) */ FIELD, /** 作用於方法 */ METHOD, /** 作用於引數宣告 */ PARAMETER, /** 作用於建構函式宣告 */ CONSTRUCTOR, /** 作用於區域性變數宣告 */ LOCAL_VARIABLE, /** 作用於註解宣告 */ ;, /** 作用於包宣告 */ PACKAGE, /** 作用於型別引數(泛型引數)宣告 */ TYPE_PARAMETER, /** 作用於使用型別的任意語句(不包括class) */ TYPE_USE } ``` TYPE_PARAMETER的用法示例 ```java class D<@PTest T> { } // 註解@PTest作用於泛型T ``` TYPE_USE的用法示例 ```java //用於父類或者介面 class Test implements @Parent TestP {} //用於建構函式 new @Test String("/usr/data") //用於強制轉換和instanceof檢查,注意這些註解中用於外部工具 //它們不會對型別轉換或者instanceof的檢查行為帶來任何影響 String path=(@Test String)input; if(input instanceof @Test String) //註解不會影響 //用於指定異常 public Person read() throws @Test IOException. //用於萬用字元繫結 List<@Test ? extends Data> List @Test String.class //非法,不能標註class ``` - @Inherited:表示**當前註解會被註解類的子類繼承**。即在子