注釋是一種形式的元數據,提供了非程序自身的數據,注釋對於被注釋的代碼沒有直接的影響。
本文主要概括注釋的使用,java平台(SE)預定義的注釋,類型注釋是如跟可插入類型系統連用達到更強的類型檢查的,以及如何實現重復注釋。
注釋有許多用途,包括:
注釋最簡單的形式如下:
@Entity
@符號提示編譯器接下來的詞是一個注釋,示例中注釋為Entity,注釋中可以包含元素,元素可以是命名的也可以是未命名的,如果注釋中僅有一個元素,則元素名稱可以省略,如果注釋中不含元素,則圓括號可以省略,可以在一個聲明中使用多個注釋,java8中可以允許使用多個相同名稱的注釋,又叫重復注釋:
//注釋中包含元素 @Author( name = "Benjamin Franklin", date = "3/27/2003" ) class MyClass() { //注釋中只有一個元素,則名稱可省略 @SuppressWarnings("unchecked") void myMethod() { ... } //... }
注釋可以應用於聲明中,包括類,字段,方法和其他變成元素的聲明。一般情況下,每個注釋占用一行。
java8 以後,注釋也可以在類型使用的使用的時候應用,如下所示:
//類實例床架表達式 new @Interned MyObject(); //類型轉化 myString = (@NonNull String) str; //實現短語 class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... } //拋出異常聲明 void monitorTemperature() throws @Critical TemperatureException { ... }
所有注釋的形式叫做類型注釋。
注釋的聲明示例:
@interface ClassPreamble { String author(); String date();
int currentRevision() default 1;
}
注釋的定義類似於接口,只不過interface關鍵詞前有@符號,實際上注釋類型是一種形式接口,注釋的主體定義包含了注釋的元素聲明,元素可以有默認值,添加默認值的方法就是在元素聲明後跟上default關鍵詞以及默認值,如上例子所示。
java se API中預定義了多個注釋類型,其中有一些是被java編譯器用的,有一些是應用與其他注釋的。
在java.lang包中預定義的注釋類型有@Deprecated,@Override和SupressWarning。
@Deprecated提示所注釋的元素已經棄用,不應該再使用。當一個被@Deprecated注釋所注釋的方法,類或者字段被使用時,編譯器將產生警告信息。當決定要棄用一個元素時,也應該在javadoc中體現,利用javadoc的@deprecated標簽,如下例所示,javadoc標簽以小寫字母開頭:
// Javadoc此處寫javadoc注釋 /** * @deprecated * explanation of why it was deprecated */ @Deprecated static void deprecatedMethod() { } }
@Override注釋用於通知編譯器該注釋所注釋的方法將覆寫父類中的方法,當然,覆寫方法不需要用@Override注釋,@Override注釋的使用能減少錯誤,如方法名稱拼寫錯誤,如果沒有成功覆寫方法,則編譯器將產生錯誤。
@SuppressWarnings注釋通知編譯器抑制指定的錯誤信息的產生,每條錯誤信息都屬於一個類型,java語言說明書中列出了兩種錯誤信息:deprecation和unchecked。
@SafeVarargs(java7及以後)注釋應用於方法或者構造器上,使用注釋時,含有可變變量的方法或者構造器將不會因為對可變變量的可能不安全的操作產生unchecked警告信息。
@FunctionalInterface注釋在java8中引入,使用該注釋表明被注釋的接口為功能接口。
被用於其他注釋的注釋叫做元注釋(meta-annotations),java.lang.annotation中有多個元注釋。
@Retention注釋指定如何存儲標記的注釋:
RetentionPolicy.SOURCE
– 標記的注釋僅僅保留在源代碼層,被編譯器忽略RetentionPolicy.CLASS
– 標記的注釋在編譯時被保留,但是會被java虛擬機忽略RetentionPolicy.RUNTIME
– 標記的注釋在java虛擬機中保留,但是在運行時被忽略@Documented注釋提示指定的注釋在使用時也應該使用javadoc工具撰寫文檔。
@Target注釋用來限制標記的注釋所使用的對象,該注釋指定以下元素類型中的一個作為其值:
ElementType.ANNOTATION_TYPE
能應用於一個注釋ElementType.CONSTRUCTOR
能應用於一個構造器ElementType.FIELD
能應用與一個注釋或者屬性ElementType.LOCAL_VARIABLE
能應用於一個局部變量ElementType.METHOD
能應用於方法層的注釋ElementType.PACKAGE
能應用於包聲明ElementType.PARAMETER
能應用於一個方法的參數ElementType.TYPE
能應用於一個類@Inherited注釋提示標記的注釋類型可以從超類繼承(默認不能繼承),當用戶未檢索到該類型的注釋時,將在其父類中檢索該注釋,該注釋僅能在類的聲明中使用。
@Repeatable注釋是從java8開始引入的,提示標記的類型可以對同一個元素使用多次。
java8以前,注釋只能用在聲明當中,java8以後,注釋可以應用於任何類使用的地方,比如類實例的創建表達式(new),轉化(cast),實現子句以及拋出子句(以上注釋的使用位置已舉例)。
類型注釋的常見可用於支持改進的類型檢查的java編程方式的分析。java8 SE自身並沒有提供類型檢查的框架,但你可以編寫或者是下載一個由一個或多個用於結合java編譯器的模塊而實現的類型檢查框架,如華盛頓大學編寫的檢查框架Checker Framework。
Reflection API中由多個方法可以用來檢索注釋,返回單個注釋的方法,如AnnotatedElement.getAnnotationByType(Class<T>),其行為沒有發生改變,java8以後,由於可以重復使用一個類型的注釋,由於兼容的原因,重復的注釋是存儲在一個注釋容器內的,由java編譯器自動生成,因此當有重復注釋時,可先獲得多個注釋的注釋容器,這樣傳統返回單個注釋的方法照樣可以使用。java8也引入了一個可以一次返回多個注釋的方法,如AnnotatedElement.getAnnotations(Class<T>)。