1. 註解的分類
標準註解
包括以下幾種註解成爲標準註解,這三種是在JDK5之後包含的標準註解(annotation)。
Overide——表示該函數被覆蓋重寫
Deprecated——表示該函數或者類被廢棄,已經不再維護
SuppressWarnings——表示告訴Java編譯器關閉對這些方法、類、成員的警告元註解
元註解表示用來自定義其他註解的註解,有以下四種。註解 用法示例 說明 @Target @Target(ElementType.METHOD) 表示該註解可以用於什麼地方,可能的ElementType參數有:
CONSTRUCTOR:構造器的聲明
FIELD:域聲明(包括enum實例)
LOCAL_VARIABLE:局部變量聲明
METHOD:方法聲明
PACKAGE:包聲明
PARAMETER:參數聲明
TYPE:類、接口(包括註解類型)或enum聲明@Retention @Retention(RetentionPolicy.RUNTIME) 表示需要在什麼級別保存該註解信息。可選的RetentionPolicy參數包括:
SOURCE:註解將被編譯器丟棄
CLASS:註解在class文件中可用,但會被VM丟棄
RUNTIME:VM將在運行期間保留註解,因此可以通過反射機制讀取註解的信息。@Documented @Documented 將註解包含在Javadoc中 @Inherited @Inherited 允許子類繼承父類中的註解 。
- 在元註解基礎上自定義的註解
2.自定義註解
沒有元素的註解叫做標記註解(mark annotation),下面就是一個標記註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MarkAnnotation {
}
下面的MethodInfo是一個比較完整的註解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
String author() default "[email protected]";
String date();
int version() default 1;
}
在MethodInfo的實現上有以下幾點
- 通過 @interface 定義,註解名即爲自定義註解名
- 註解配置參數名爲註解類的方法名,且:
a. 所有方法沒有方法體,沒有參數沒有修飾符,實際只允許 public & abstract 修飾符,默認爲 public ,不允許拋異常
b. 方法返回值只能是基本類型,String, Class, annotation, enumeration 或者是他們的一維數組
c. 若只有一個默認屬性,可直接用 value() 函數。一個屬性都沒有表示該 Annotation 爲 Mark Annotation 可以加 default 表示默認值
註解的可用的類型包括以下幾種:所有基本類型、String、Class、enum、Annotation、以上類型的數組形式。元素不能有不確定的值,即要麼有默認值,要麼在使用註解的時候提供元素的值。而且元素不能使用null作爲默認值。註解在只有一個元素且該元素的名稱是value的情況下,在使用註解的時候可以省略“value=”,直接寫需要的值即可。
3.註解的使用
還是以上面的MethodInfo爲例,該註解是一個方法註解。
public Example{
@MethodInfo(author="gaoyan", date="2015-05-30", version=2)
public boolean isGoodExample() {
return true;
}
@MethodInfo(date="2015-05-30")
public boolean isBadExample() {
return false;
}
}
4.註解的解析
- 運行時的Annotation解析
對於@Retention(RetentionPolicy=RUNTIME)、@Target(ElementType.METHOD)的Annotation,可以使用下面的API解析:
method.getAnnotation(AnnotationName.class);
method.getAnnotations();
method.isAnnotationPresent(AnnotationName.class);
其他 @Target 如 Field,Class 方法類似
- getAnnotation(AnnotationName.class) 表示得到該 Target 某個 Annotation 的信息,因爲一個 Target 可以被多個 Annotation 修飾
- getAnnotations() 則表示得到該 Target 所有 Annotation
- isAnnotationPresent(AnnotationName.class) 表示該 Target 是否被某個 Annotation 修飾
public static void main(String[] args) {
try {
Class cls = Class.forName("Example");
for (Method method : cls.getMethods()) {
MethodInfo methodInfo = method.getAnnotation(
MethodInfo.class);
if (methodInfo != null) {
System.out.println("method name:" + method.getName());
System.out.println("method author:" + methodInfo.author());
System.out.println("method version:" + methodInfo.version());
System.out.println("method date:" + methodInfo.date());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
編譯時的Annotation解析
編譯時 Annotation 指 @Retention 爲 CLASS 的 Annotation,甴編譯器自動解析。需要做的- 自定義類集成自 AbstractProcessor
- 重寫其中的 process 函數
假設 MethodInfo 的 @Retention 爲 CLASS,解析示例如下:
@SupportedAnnotationTypes({ "MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
HashMap<String, String> map = new HashMap<String, String>();
for (TypeElement te : annotations) {
for (Element element : env.getElementsAnnotatedWith(te)) {
MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
map.put(element.getEnclosingElement().toString(), methodInfo.author());
}
}
return false;
}
}
SupportedAnnotationTypes 表示這個 Processor 要處理的 Annotation 名字。
process 函數中參數 annotations 表示待處理的 Annotations,參數 env 表示當前或是之前的運行環境
process 函數返回值表示這組 annotations 是否被這個 Processor 接受,如果接受後續子的 rocessor 不會再對這個 Annotations 進行處理