Java
注解(Annotation
)又稱Java
標注名段,是JDK5中引入的一種注釋機制躏惋。Annotation
其實是代碼中的特殊標記红氯,這些標記可以在編譯框咙、類加載、運行時被讀取痢甘,并執(zhí)行相應(yīng)的處理喇嘱。通過使用注解,開發(fā)人員可以在不改變原有邏輯的情況下塞栅,在源文件中嵌入一些補充信息者铜。
1.注解的聲明
與聲明一個"Class"不同的是,注解的聲明使用 @interface 關(guān)鍵字。一個注解的聲明如下:
public @interface AnnotationTest {}
2.元注解
在定義注解時作烟,注解類也能夠使用其他的注解聲明愉粤。對注解類型進行注解的注解類,我們稱之為 meta annotation
(元注解)拿撩。一般情況下衣厘,我們在定義自定義注解時,需要指定的元注解主要有兩個:@Retention压恒、@Target
影暴,對于@Documented和@Inherited
用的相對較少,下面我們看下這些元注解探赫。
2.1 注解@Retention
@Retention
只能用于修飾Annotation
定義型宙,用于指定被修飾的Annotation
可以保留多長時間。
Annotation
的保留有三種方式:
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME;
private RetentionPolicy() {
}
}
- RetentionPolicy.SOURCE: 標記的注解僅保留到源碼級別中伦吠,并被編譯器忽略妆兑。
- RetentionPolicy.CLASS: 標記的注解在編譯時由編譯器保留,但 Java 虛擬機(JVM)會忽略毛仪。
- RetentionPolicy.RUNTIME: 標記的注解由 JVM 保留搁嗓,因此運行時環(huán)境可以使用它。
@Retention 三個值中 SOURCE < CLASS < RUNTIME潭千,即CLASS包含了SOURCE谱姓,RUNTIME包含SOURCE借尿、
CLASS刨晴。
示例:
@Retention(RetentionPolicy.RUNTIME) //注解保留在運行時
public @interface AnnotationTest {
}
2.2 注解@Target
@Target
注解標記另一個注解,以限制可以應(yīng)用注解的Java
元素類型路翻。目標注解指定以下元素類型之一作為其值:
package java.lang.annotation;
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE,
TYPE_PARAMETER,
TYPE_USE;
private ElementType() {
}
}
- ElementType.TYPE: 可以應(yīng)用于類的任何元素狈癞。
- ElementType.FIELD: 可以應(yīng)用于字段或?qū)傩浴?/li>
- ElementType.METHOD: 可以應(yīng)用于方法級注解。
- ElementType.PARAMETER: 可以應(yīng)用于方法的參數(shù)茂契。
- ElementType.CONSTRUCTOR: 可以應(yīng)用于構(gòu)造函數(shù)蝶桶。
- ElementType.LOCAL_VARIABLE: 可以應(yīng)用于局部變量。
- ElementType.ANNOTATION_TYPE: 可以應(yīng)用于注解類型掉冶。
- ElementType.PACKAGE: 可以應(yīng)用于包聲明真竖。
- ElementType.TYPE_PARAMETER:可以用于類型參數(shù)聲明(1.8新加入)
- ElementType.TYPE_USE:可以用于類型使用聲明(1.8新加入)
示例:
@Retention(RetentionPolicy.RUNTIME) //注解保留在運行時
@Target(ElementType.METHOD) //只可以用于方法級注解
public @interface AnnotationTest {
}
2.3 注解@Documented
@Documented注解用于被javadoc工具提取成文檔
@Documented
public @interface AnnotationTest {
}
2.4 注解@Inherited
@Inherited表示允許子類繼承父類中定義的注解。
示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited // 1
public @interface Inheritable {
}
我們對Inheritable
注解添加元注解@Inherited
厌小,則Inheritable
注解具有繼承性恢共。
@Inheritable
public class Base {
}
我們Base類使用了@Inheritable
注解,其子類也將使用@Inheritable
注解
public class ChildAnnotation extends Base {
public static void main(String[] args) {
System.out.println(ChildAnnotation.class.isAnnotationPresent(Inheritable.class));
}
}
我們的ChildAnnotation
類繼承自Base
類璧亚,然后運行結(jié)果為true讨韭。
如果我們將上面 “1”注釋掉,那么@Inheritable
將不具有繼承性,其運行結(jié)果為false透硝。
3.注解元素類型
通過上述對@AnnotationTest注解的定義狰闪,我們了解了注解定義的過程,由于@AnnotationTest內(nèi)部沒有定義其他元素濒生,所以@AnnotationTest也稱為標記注解埋泵,但在自定義注解中,一般都會包含一些元素以表示某些值甜攀,方便處理器使用秋泄,這點在下面的例子將會看到:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnotationTest {
String value() default "";
}
我們聲明了一個String
類型的value
元素,默認是空字符串规阀,須注意到對應(yīng)任何元素的聲明應(yīng)采用方法的聲明方式恒序,同時可選擇使用default
提供默認值。
@AnnotationTest(value = "123")
public class Test {
}
而對于上面沒有使用default
默認值谁撼,我們在使用的時候就必須去指定@AnnotationTest(value = "123")
否則編譯器會報錯歧胁, 使用了default
默認值就可以直接使用@AnnotationTest
可以去管value
了
注解支持的元素數(shù)據(jù)類型除了上述的String,還支持如下數(shù)據(jù)類型:
- 所有基本類型(int,float,boolean,byte,double,char,long,short)
- String
- Class
- enum
- Annotation
- 上述類型的數(shù)組
倘若使用了其他數(shù)據(jù)類型厉碟,編譯器將會丟出一個編譯錯誤喊巍,注意,聲明注解元素時可以使用基本類型但不允許使用任何包裝類型箍鼓,同時還應(yīng)該注意到注解也可以作為元素的類型崭参,也就是嵌套注解。
4.注意
編譯器對默認值的限制
編譯器對元素的默認值有嚴格的要求款咖。元素要么具有默認值何暮,要么在使用注解時提供元素的值。其次铐殃,對于非基本類型的元素海洼,無論是在源代碼中聲明,還是在注解接口中定義默認值富腊,都不能以null作為值坏逢,這就是限制,但造成一個元素的存在或缺失狀態(tài)赘被,因為每個注解的聲明中是整,所有的元素都存在,并且都具有相應(yīng)的值民假,為了繞開這個限制浮入,只能定義一些特殊的值,例如空字符串或負數(shù)阳欲,表示某個元素不存在舵盈。
注解不支持繼承
注解是不支持繼承的陋率,因此不能使用關(guān)鍵字extends
來繼承某個@interface
,但注解在編譯后秽晚,編譯器會自動繼承java.lang.annotation.Annotation
接口瓦糟,即使Java
的接口可以實現(xiàn)多繼承,但定義注解時依然無法使用extends
關(guān)鍵字繼承@interface
赴蝇。