目錄
一、介紹
二、注解聲明
三、注解使用
四、預定義的注解類型
4.1、被編譯器使用的注解
@Deprecated
@Override
@SuppressWarnings
4.2、用于其他注解的注解
@Retention
@Documented
@Target
@Inherited
@Repeatable
五、其他
參考:
一、介紹
注解(annotation),一種中繼資料,提供一些關于程式的資料,但不是程式的一部分,對程式的執行沒有直接的影響。
注解有三種用處:提供資訊給編譯器,指導編譯器行為;提供建構資訊給建構工具,這些工具有ant、mavent等,建構工具會根據這些注解産生源碼或其他檔案;運作時提供資訊,可以通過反射來獲得這些注解資訊。
定義的注解預設繼承于java.lang.annotation.Annotation接口,是以你可以繼承該注解,但是沒多大的實際用處。
二、注解聲明
@Retention(RetentionPolicy.RUNTIME)
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
注解聲明與接口類似,多了個@。注解中的元素聲明與接口方法類似,元素也可以賦予預設值,通過default實作。注解的元素類型隻能是基本類型、數組、字元串、枚舉、注解、Class。定義該注解時可以被其他元注解注釋,如上面的@Retention,該注解說明自定義的注解ClassPreamble可以儲存到運作時。
三、注解使用
注解一般可以使用在類、方法、字段等java元素上,這是在定義注解時聲明的通過Target設定的。如:
@Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
class MyClass() { ... }
如果隻有一個元素,該元素名字為value的情況下,名字可以忽略:
@SuppressWarnings(value = "unchecked")
void myMethod() { ... }
可以寫成如下方式
@SuppressWarnings("unchecked")
void myMethod() { ... }
如果有多個元素,其他的有預設值,value元素沒有,也可以忽略其他元素,和value名字:
@MyAnnotation("aaa")
class A<T,Y>{
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
public String value();
public String name() default "";
}
如果沒有元素或者都有預設值,連括号也可以忽略:
@EBook
class MyClass { ... }
如果元素是數組,且賦予數組一個值,則不需要大括号:
@MyAnnotation("aaa")
class A<T,Y>{
}
@MyAnnotation({"bbb","ccc"})
class B{
}
@MyAnnotation("aaa","bbb")
class C{
}
@interface MyAnnotation{
String[] value();
String[] name() default "bbb";
}
四、預定義的注解類型
java se api中已經定義了一些注解,可以用于編譯器和用于其他注解。
4.1、被編譯器使用的注解
@Deprecated
告訴編譯器被注解的元素是被棄用的,使用會被編譯器警告。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
可以看出,@Deprecated可以被使用到很多地方,不局限于方法、類、字段。可以配合javadoc的@deprecated标簽使用,通過該标簽解釋下為何棄用。
// Javadoc comment follows
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
}
@Override
通知編譯器被注釋的方法必須覆寫父類方法。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@SuppressWarnings
用于抑制警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
還有其他的如@SafeVarargs、@FunctionalInterface。
4.2、用于其他注解的注解
用于注釋其他注解的注解稱為元注解。
@Retention
指定被标記的注解如何被存儲,比如存在源碼中、位元組碼中、運作時中。如果@Retention不存在,則預設使用
RetentionPolicy.CLASS政策,就是存在位元組碼中。
-
– The marked annotation is retained only in the source level and is ignored by the compiler.RetentionPolicy.SOURCE
-
– The marked annotation is retained by the compiler at compile time, but is ignored by the Java Virtual Machine (JVM).RetentionPolicy.CLASS
-
– The marked annotation is retained by the JVM so it can be used by the runtime environment.RetentionPolicy.RUNTIME
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
@Documented
被@Document注釋的注解在其他地方被使用時,可以顯示在javadoc導出的文檔中。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Target
指定注解可以使用在哪種java元素上:
-
can be applied to an annotation type.ElementType.ANNOTATION_TYPE
-
can be applied to a constructor.ElementType.CONSTRUCTOR
-
can be applied to a field or property.ElementType.FIELD
-
can be applied to a local variable.ElementType.LOCAL_VARIABLE
-
can be applied to a method-level annotation.ElementType.METHOD
-
can be applied to a package declaration.ElementType.PACKAGE
-
can be applied to the parameters of a method.ElementType.PARAMETER
-
can be applied to any element of a class.ElementType.TYPE
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
@Inherited
訓示注解可以被繼承。假設被@Inherited注釋的注解為@A,如果父類被@A注釋,子類便可以繼承這個注解。但是并不完全對,因為通過反射,子類不能找到@A。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
@Repeatable
被@Repeatable注解的注解可以在一個地方使用多次,比如下面的@Schedule可以使用多次:
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
但是由于相容原因,repeatable注解(就是被@Repeatable注釋過的注解)需要被存入容器注解(container annotation)。也就是說定義repeatable注解時還需要定義容器注解。下面聲明repeatable注解:
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
@Repeatable中需要指定容器注解,容器注解的定義為:
public @interface Schedules {
Schedule[] value();
}
注意,容器注解的元素value數組中的類型一定要為repeatable注解類型。很拗口吧,但是既然要存入repeatable注解(也就是Schedule),當然要定義它的數組(Schedule[])。
五、其他
一些注解可以用于類型的使用上,被稱為類型注解(type annotation),通常被用于類型檢測。
參考:
https://docs.oracle.com/javase/tutorial/java/annotations/index.html
http://tutorials.jenkov.com/java/annotations.html
https://www.developer.com/java/other/article.php/10936_3556176_3/An-Introduction-to-Java-Annotations.htm
https://blog.usejournal.com/how-much-do-you-actually-know-about-annotations-in-java-b999e100b929