Java註解全面解析
Java註解全面解析
1.基本語法
註解定義看起來很像介面的定義。事實上,與其他任何介面一樣,註解也將會編譯成class檔案。
@Target(ElementType.Method)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
除了@符號以外,@Test的定義很像一個空的介面。定義註解時,需要一些元註解(meta-annotation),如@Target和@Retention
@Target用來定義註解將應用於什麼地方(如一個方法或者一個域)
@Retention用來定義註解在哪一個級別可用,在原始碼中(source),類檔案中(class)或者執行時(runtime)
在註解中,一般都會包含一些元素以表示某些值。當分析處理註解時,程式可以利用這些值。沒有元素的註解稱為標記註解(marker annotation)
四種元註解,元註解專職負責註解其他的註解,所以這四種註解的Target值都是ElementType.ANNOTATION_TYPE
註解 | 說明 |
---|---|
@Target | 表示該註解可以用在什麼地方,由ElementType列舉定義 CONSTRUCTOR:構造器的宣告 FIELD:域宣告(包括enum例項) LOCAL_VARIABLE:區域性變數宣告 METHOD:方法宣告 PACKAGE:包宣告 PARAMETER:引數宣告 TYPE:類、介面(包括註解型別)或enum宣告 ANNOTATION_TYPE:註解宣告(應用於另一個註解上) TYPE_PARAMETER:型別引數宣告(1.8新加入) TYPE_USE:型別使用宣告(1.8新加入) PS:當註解未指定Target值時,此註解可以使用任何元素之上,就是上面的型別 |
@Retention | 表示需要在什麼級別儲存該註解資訊,由RetentionPolicy列舉定義 SOURCE:註解將被編譯器丟棄(該型別的註解資訊只會保留在原始碼裡,原始碼經過編譯後,註解資訊會被丟棄,不會保留在編譯好的class檔案裡) CLASS:註解在class檔案中可用,但會被VM丟棄(該型別的註解資訊會保留在原始碼裡和class檔案裡,在執行的時候,不會載入到虛擬機器(JVM)中) RUNTIME:VM將在執行期也保留註解資訊,因此可以通過反射機制讀取註解的資訊(原始碼、class檔案和執行的時候都有註解的資訊) PS:當註解未定義Retention值時,預設值是CLASS |
@Documented | 表示註解會被包含在javaapi文件中 |
@Inherited | 允許子類繼承父類的註解 |
2. 註解元素
– 註解元素可用的型別如下:
– 所有基本型別(int,float,boolean,byte,double,char,long,short)
– String
– Class
– enum
– Annotation
– 以上型別的陣列
如果使用了其他型別,那編譯器就會報錯。也不允許使用任何包裝型別。註解也可以作為元素的型別,也就是註解可以巢狀。
元素的修飾符,只能用public或default。
– 預設值限制
編譯器對元素的預設值有些過分挑剔。首先,元素不能有不確定的值。也就是說,元素必須要麼具有預設值,要麼在使用註解時提供元素的值。
其次,對於非基本型別的元素,無論是在原始碼中宣告,還是在註解介面中定義預設值,都不能以null作為值。這就是限制,這就造成處理器很難表現一個元素的存在或缺失狀態,因為每個註解的宣告中,所有的元素都存在,並且都具有相應的值。為了繞開這個限制,只能定義一些特殊的值,例如空字串或負數,表示某個元素不存在。
@Target(ElementType.Method)
@Retention(RetentionPolicy.RUNTIME)
public @interface MockNull {
public int id() default -1;
public String description() default “”;
}
3. 快捷方式
何為快捷方式呢?先來看下springMVC中的Controller註解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
String value() default “”;
}
可以看見Target應用於類、介面、註解和列舉上,Retention策略為RUNTIME執行時期,有一個String型別的value元素。平常使用的時候基本都是這樣的:
@Controller(“/your/path”)
public class MockController { }
這就是快捷方式,省略了名-值對的這種語法。下面給出詳細解釋:
註解中定義了名為value的元素,並且在應用該註解的時候,如果該元素是唯一需要賦值的一個元素,那麼此時無需使用名-值對的這種語法,而只需在括號內給出value元素所需的值即可。這可以應用於任何合法型別的元素,當然了,這限制了元素名必須為value。
4. JDK1.8註解增強
TYPE_PARAMETER和TYPE_USE
在JDK1.8中ElementType多了兩個列舉成員,TYPE_PARAMETER和TYPE_USE,他們都是用來限定哪個型別可以進行註解。舉例來說,如果想要對泛型的型別引數進行註解:
public class AnnotationTypeParameter<@TestTypeParam T> {}
那麼,在定義@TestTypeParam時,必須在@Target設定ElementType.TYPE_PARAMETER,表示這個註解可以用來標註型別引數。例如:
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestTypeParam {}
ElementType.TYPE_USE用於標註各種型別,因此上面的例子也可以將TYPE_PARAMETER改為TYPE_USE,一個註解被設定為TYPE_USE,只要是型別名稱,都可以進行註解。例如有如下註解定義:
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
那麼以下的使用註解都是可以的:
List<@Test Comparable> list1 = new ArrayList<>();
List<? extends Comparable> list2 = new ArrayList<@Test Comparable>();
@Test String text;
text = (@Test String)new Object();
java.util. @Test Scanner console;
console = new java.util.@Test Scanner(System.in);
PS:以上@Test註解都是在型別的右邊,要注意區分1.8之前的列舉成員,例如:
@Test java.lang.String text;
在上面這個例子中,顯然是在進行text變數標註,所以還使用當前的@Target會編譯錯誤,應該加上ElementType.LOCAL_VARIABLE。
@Repeatable註解
@Repeatable註解是JDK1.8新加入的,從名字意思就可以大概猜出他的意思(可重複的)。可以在同一個位置重複相同的註解。舉例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filter {
String [] value();
}
如下進行註解使用:
@Filter({“/admin”,”/main”})
public class MainFilter { }
換一種風格:
@Filter(“/admin”)
@Filter(“/main”)
public class MainFilter {}
在JDK1.8還沒出現之前,沒有辦法到達這種“風格”,使用1.8,可以如下定義@Filter:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Filters.class)
public @interface Filter {
String value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filters {
Filter [] value();
}
實際上這是編譯器的優化,使用@Repeatable時告訴編譯器,使用@Filters來作為收集重複註解的容器,而每個@Filter儲存各自指定的字串值。
JDK1.8在AnnotatedElement介面新增了getDeclaredAnnotationsByType和getAnnotationsByType,在指定@Repeatable的註解時,會尋找重複註解的容器中。相對於,getDeclaredAnnotation和getAnnotation就不會處理@Repeatable註解。舉例如下:
@Filter(“/admin”)
@Filter(“/filter”)
public class FilterClass {
public static void main(String[] args) {
Class<FilterClass> filterClassClass = FilterClass.class;
Filter[] annotationsByType = filterClassClass.getAnnotationsByType(Filter.class);
if (annotationsByType != null) {
for (Filter filter : annotationsByType) {
System.out.println(filter.value());
}
}
System.out.println(filterClassClass.getAnnotation(Filter.class));
}
}
日誌如下:
/admin
/filter
null
原創文章轉載請註明出處:Java註解全面解析
原創文章,轉載請註明: 轉載自併發程式設計網 – ifeve.com本文連結地址: Java註解全面解析
相關文章
- Java 註解全面解析Java
- Java 註解完全解析Java
- Java註解解析-基礎+執行時註解(RUNTIME)Java
- Java註解解析-搭建自己的註解處理器(CLASS註解使用篇)Java
- java自定義註解學習(三)_註解解析及應用Java
- 基礎篇:深入解析JAVA註解機制Java
- Java 中泛型的全面解析Java泛型
- java註解Java
- 註解 javaJava
- Java雜記17—String全面解析Java
- Java註解詳解Java
- Java 註解詳解Java
- JAVA-註解(2)-自定義註解及反射註解Java反射
- 註解專題(一)Java元註解,內建註解Java
- this 全面解析
- this全面解析
- Java中的註解-自定義註解Java
- JAVA 註解 AnnontationJava
- Java註解AnnotatonJava
- Java反射-註解Java反射
- Java™ 教程(註解)Java
- Java —— 註解(Annotation)Java
- Java(5)註解Java
- java註解,反射Java反射
- Java Annotation 註解Java
- Java--註解Java
- Java 註解(Annotation)Java
- 註解式專案開發!詳細解析Java中各個註解的作用和使用方式Java
- Java註解詳解「註解專案實戰」Java
- Java註解(Annotation)詳解Java
- 深入理解 Java 註解 [元註解(一)]Java
- 最全面的Java多執行緒用法解析Java執行緒
- this全面解析(二)
- this 全面解析(一)
- JavaScriptCore全面解析JavaScript
- VLayout全面解析
- Java 8 註解探秘Java
- 自定義JAVA註解Java