本文是對網絡中相關文章的總結,再加上自己的相關見解得出的,若有侵權請及時聯系
學習博客鏈接:
Java 注解(Annotation)
元注解
元注解是可以注解到注解上的注解,或者說元注解是一種基本注解,但是它能夠應用到其它的注解上面。元注解分以下5類:
@Retention - 標識這個注解怎么保存
Retention 的英文意為保留期的意思。當 @Retention 應用到一個注解上的時候,它解釋說明了這個注解的的存活時間。
Retention的取值如下:
- RetentionPolicy.SOURCE 注解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視
- RetentionPolicy.CLASS 注解只被保留到編譯進行的時候,它并不會被加載到 JVM 中
- RetentionPolicy.RUNTIME 注解可以保留到程序運行的時候,它會被加載進入到 JVM 中,所以在程序運行時可以獲取到它們。
每一個Annotation對象,都會有唯一的RetentionPolicy屬性。
@Documented - 標記這些注解是否包含在用戶文檔中。
顧名思義,這個元注解肯定是和文檔有關。它的作用是能夠將注解中的元素包含到 Javadoc 中去。
@Target - 標記這個注解應該是哪種 Java 成員。
Target 是目標的意思,@Target 指定了注解運用的地方。
你可以這樣理解,當一個注解被 @Target 注解時,這個注解就被限定了運用的場景。
@Target 有下面的取值:
- ElementType.ANNOTATION_TYPE 可以給一個注解進行注解
- ElementType.CONSTRUCTOR 可以給構造方法進行注解
- ElementType.FIELD 可以給屬性進行注解
- ElementType.LOCAL_VARIABLE 可以給局部變量進行注解
- ElementType.METHOD 可以給方法進行注解
- ElementType.PACKAGE 可以給一個包進行注解
- ElementType.PARAMETER 可以給一個方法內的參數進行注解
- ElementType.TYPE 可以給一個類型進行注解,比如類、接口、枚舉
對于每 1 個 Annotation 對象,可以有若干個 ElementType 屬性
@Inherited - 標記這個注解是繼承于哪個注解類(默認 注解并沒有繼承于任何父類)
Inherited 是繼承的意思,但是它并不是說注解本身可以繼承,而是說如果一個超類(是一個類,不是注解)被 @Inherited 注解過的注解進行注解的話,那么如果它的子類沒有被任何注解應用的話,那么這個子類就繼承了超類的注解。
子類可以擁有父類被標明了@Inherited的注解
@Repeatable
Repeatable 自然是可重復的意思。@Repeatable 是 Java 1.8 才加進來的,所以算是一個新的特性(所以有些地方說元注解只有4個,其實往后還有添加新的)
被標明了@Repeatable
的注解可以重復使用,多次修飾一個注解
內置的注解
- @Override - 檢查該方法是否是重寫方法。如果發現其父類,或者是引用的接口中并沒有該方法時,會報編譯錯誤。
- @Deprecated - 標記過時方法。如果使用該方法,會報編譯警告。
- @SuppressWarnings - 指示編譯器去忽略注解中聲明的警告,他的相關參數(也就是下面說到的注解的屬性)如下:(使用形式如下:@SuppressWarnings(value={"deprecation"}))
- deprecation -- 使用了不贊成使用的類或方法時的警告
- unchecked -- 執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型。
- fallthrough -- 當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告。
- path -- 在類路徑、源文件路徑等中有不存在的路徑時的警告。
- serial -- 當在可序列化的類上缺少 serialVersionUID 定義時的警告。
- finally -- 任何 finally 子句不能正常完成時的警告。
- all -- 關于以上所有情況的警告。
- @SafeVarargs - Java 7 開始支持,忽略任何使用參數為泛型變量的方法或構造函數調用產生的警告。
- @FunctionalInterface - Java 8 開始支持,標識一個匿名函數或函數式接口。
注解的基本語法
annotation通用定義
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}
@interface ---> 注解的定義關鍵字
使用 @interface 定義注解時,意味著它實現了 java.lang.annotation.Annotation 接口,即該注解就是一個Annotation。
定義 Annotation 時,@interface 是必須的。
注意:它和我們通常的 implemented 實現接口的方法不同。Annotation 接口的實現細節都由編譯器完成。通過 @interface 定義注解后,該注解不能繼承其他的注解或接口。
注解的屬性
注解的屬性也叫做成員變量。注解只有成員變量,沒有方法。注解的成員變量在注解的定義中以“無形參的方法”形式來聲明,其方法名定義了該成員變量的名字,其返回值定義了該成員變量的類型。
實例分析:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg();
}
上面代碼定義了 TestAnnotation 這個注解中擁有 id 和 msg 兩個屬性。在使用的時候,我們應該給它們進行賦值。
賦值的方式是在注解的括號內以 value=”” 形式,多個屬性之前用 ,隔開。
@TestAnnotation(id=3,msg="hello annotation")
public class Test {}
需要注意的是,在注解中定義屬性時它的類型必須是 8 種基本數據類型 外加 類、接口、注解及它們的數組。
注解中屬性可以有默認值,默認值需要用 default 關鍵值指定。比如:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
另外,還有一種情況。如果一個注解內僅僅只有一個名字為 value 的屬性時,應用這個注解時可以直接接屬性值填寫到括號內。如:@Check("hi")
注解與反射
注解通過反射獲取。首先可以通過 Class 對象的 isAnnotationPresent() 方法判斷它是否應用了某個注解:
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
然后通過 getAnnotation() 方法來獲取 Annotation 對象:
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是 getAnnotations() 方法:
public Annotation[] getAnnotations() {}
以上方法的使用場景:
- 編寫AOP的時候,獲取注解中的具體參數
注解的作用
注解有許多用處,主要如下:
- 提供信息給編譯器:編譯器可以利用注解來探測錯誤和警告信息
- 編譯階段時的處理: 軟件工具可以用來利用注解信息來生成代碼、Html文檔或者做其它相應處理。
- 運行時的處理: 某些注解可以在程序運行的時候接受代碼的提取
值得注意的是,注解不是代碼本身的一部分。