使用註解
什麼是註解
註解的作用
編譯器使用的註解
註解定義配置參數
註解配置注意事項
總結
定義註解
簡介
元註解
@Target
@Retention
生命週期
@Repeatable
@Inherited
定義Annotation步驟
總結
處理註解
讀取RUNTIME類型註解
isAnnotationPresent
getAnnotation
讀取註解的方式
getParameterAnnotations()
總結
使用註解
什麼是註解
註解是放在Java源碼的類、方法、字段、參數前的一種標籤
@Resource("hello") // 註解
public class Hello {
@Inject // 註解
int n;
@PostConstruct // 註解
public void hello(@Param String name) {
System.out.println(name);
}
@Override // 註解
public String toString() {
return "hello";
}
}
註解的作用
- 註解本身對代碼邏輯沒有任何影響
- 如何使用註解由工具來決定
編譯器使用的註解
- @Override 讓編譯器檢查該方法是否正確地實現了覆寫
@Override
public String toString() {
return "hello";
}
- @Deprecated 告訴編譯器該方法已經被標記爲“作廢”,在其他地方飲用將會出現編譯警告
@Deprecated
public void hello(String name) {
System.out.println(name);
}
- @SuppressWarnings 忽略警告
@SuppressWarnings
public void hello() {
int n; // local variable n is not used;
}
註解定義配置參數
- 配置參數由註解類型定義
- 配置參數可以包括
- 所有基本類型
- String
- 枚舉類型
- 數組
- 配置參數值必須是常量
註解配置注意事項
-
缺少某個配置參數將使用默認值
-
如果只寫常量,相當於省略了value參數
-
如果只寫註解,相當於全部使用默認值
總結
- 註解(Annotation)是Java語言用於工具處理的標註
- 註解可以配置參數,沒有指定配置的參數使用默認值
- 如果參數名稱是value,可以省略參數名稱
定義註解
簡介
使用@interface定義註解(Annotation)
- 註解的參數類似無參數方法
- 可以設定一個默認值(推薦)
- 把最常用的參數命名爲value(推薦)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
元註解
可以修飾其他註解的註解稱爲元註解
@Target
使用@Target定義Annotation指定註解可以被應用於源碼的哪些位置,可定義單個或多個:
- 類或接口:ElementType.TYPE
- 字段:ElementType.FIELD
- 方法:ElementType.METHOD
- 構造方法:ElementType.CONSTRUCTOR
- 方法參數:ElementType.PARAMETER
//@Target(ElementType.METHOD)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
@Retention
使用R@Retention定義Annotation的生命週期:
- 僅編譯期:RetentionPolicy.SOURCE
- 僅class文件:RetentionPolicy.CLASS
- 運行期:RetentionPolicy.RUNTIME
如果@Retention不存在,則該Annotation默認爲CLASS
通常自定義的Annotation都是RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
生命週期
Annotation的生命週期
- RetentionPolicy.SOURCE:編譯器在編譯時直接丟棄註解
- RetentionPolicy.CLASS:該Annotation僅存儲在class文件中
- RetentionPolicy.RUNTIME:在運行期可以讀取該Annotation
@Repeatable
使用@Repeatable定義Annotation是否可重複
- JDK >= 1.8
// 定義註解,設置可重複
@Repeatable
@Target(ElementType.TYPE)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
// 使用註解
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {
}
@Inherited
使用@Inherited定義子類是否可繼承父類定義的Annotation
- 僅針對@Target爲TYPE類型的Annotation
- 僅針對class的繼承
- 對interface的繼承無效
// 定義註解,設置可繼承
@Inherited
@Target(ElementType.TYPE)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
// 在父類使用註解
public class Person {
}
// 子類自動會繼承父類的Report註解
public class Student extends Person {
}
定義Annotation步驟
- 用@interface定義註解
- 用元註解(meta annotation)配置註解
- Target:必須設置
- Retention:一般設置爲RUNTIME
- 通常不必寫@Inherited,@Repeatable等等
- 定義註解參數和默認值
// 2.1
@Target(ElementType.TYPE)
// 2.2
@Retention(RetentionPolicy.RUNTIME)
// 1
public @interface Report {
// 3
int type() default 0;
String level() default "info";
String value() default "";
}
總結
- 使用@interface定義註解
- 可定義多個參數和默認值,核心參數使用value名稱
- 必須是指@Target來制定Annotation可以應用的範圍
- 應當設置@Retention爲RUNTIME便於運行期讀取該Annotation
處理註解
讀取RUNTIME類型註解
- Annotation也是class
- 所有Annotation繼承自java.lang.annotation.Annotation
- 使用反射API讀取
isAnnotationPresent
isAnnotationPresent(Annotation.class)方法用於判斷某個註解是否存在
- Class.isAnnotationPresent(Class)
- Field.isAnnotationPresent(Class)
- Method.isAnnotationPresent(Class)
- Constructor.isAnnotationPresent(Class)
Class cls = Person.class;
// 判斷Person類是否存在Report註解
cls.isAnnotationPresent(Report.class);
getAnnotation
getAnnotation(Annotation.class)用於獲取某個註解
- Class.getAnnotation(Class)
- Field.getAnnotation(Class)
- Method.getAnnotation(Class)
- Constructor.getAnnotation(Class)
Class cls = Person.class;
// 獲取註解,如果沒有返回null
Report report = cls.getAnnotation(Report.class);
// 獲取註解的值
int type = report.type();
String level = report.level();
讀取註解的方式
Class cls = Person.class;
// 1、先判斷是否有註解
if (cls.isAnnotationPresent(Report.class)) {
// 2、獲取註解
Report report = cls.getAnnotation(Report.class);
...
}
Class cls = Person.class;
// 1、直接獲取註解
Report report = cls.getAnnotation(Report.class);
// 2、判斷是否爲null
if (report != null) {
...
}
getParameterAnnotations()
getParameterAnnotations()方法用於讀取方法參數中的註解,返回結果是一個二位數組,每個參數的註解是一個一維數組。
// 方法參數使用註解
public String hello(@Notnull @Range(max=5) String name, @NotNull String prefix) {
...
}
Method m = ...
// 獲取方法參數中的所有註解
Annotation[][] annos = m.getParameterAnnotations();
// 獲取第一個參數中的所有註解
Annotation[] annosOfName = annos[0];// name參數的Annotation
for (Annotation anno : annosOfName) {
if (anno instanceof Range) {
Range r = (Range)anno;
...
}
}
// 註解二位數組
{
{@NotNull, @Range},
{@NotNull}
}
總結
- 可以在運行期通過反射讀取RUNTIME類型的註解,不要漏寫@Retention(RetentionPolicy.RUNTIME)
- 可以通過工具處理註解來實現相應的功能
- 對JavaBean的屬性值按規則進行檢查
- JUnit會自動運行@Test註解的測試方法