Java註解

使用註解
  什麼是註解
  註解的作用
  編譯器使用的註解
  註解定義配置參數
  註解配置注意事項
  總結
定義註解
  簡介
  元註解
    @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註解的測試方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章