1. 程式人生 > >Java基礎筆記(註解)

Java基礎筆記(註解)

1 註解

註解是放在Java原始碼的類、方法、欄位、引數前的一種標籤。 註解本身對程式碼的邏輯沒有任何影響,如何使用註解是有工具決定的,比如編輯器可以使用註解,它可以使用JDKd定義的註解,註解本身對程式碼沒有影響,但寫了註解,編譯器可以幫助我們解決問題,不寫就不檢查,JDK定義的常用註解有:

  • @Override:讓編譯器檢查該方法是否正確地實現覆寫
  • @Deprecated:告訴編譯器該方法已經作廢,在別處使用會出現警告
  • @SuppressWarning:取消警告

1.1 定義註解

使用註解的時候可以傳入配置引數,配置引數在建立註解型別時定義,配置引數可以包括:

  • 所有基本型別
  • String
  • 列舉型別
  • 基本型別的陣列

傳入配置引數必須是常量而不能是變數,如果缺少某個配置引數將使用預設值,如果只寫常量,相當於將該常量賦值給 value 引數,如果只寫註解,相當於全部使用預設值。

定義註解的時候,使用 @interface 定義註解

  • 註解的引數宣告類似宣告一個無引數方法
  • 可以設定一個預設值
  • 推薦把最常用的引數命名為 value

eg:

public @interface Report {
	int type() default 0;
	String value() default "";
}

1.1.1 元註解

有一些註解可以修飾其他的註解,把這些註解稱為元註解。

1.1.1.1 @Target
註解

使用 @Target 註解可以規定被修飾的註解能應用在原始碼的哪個位置:

  • ElementType.TYPE:類或介面
  • ElementType.FIELD:欄位
  • ElementType.METHOD:方法
  • ElementType.CONSTRUCTOR:構造方法
  • ElementType.PARAMETER:方法引數

eg:

@Target({
	ElementType.FIELD,
	ElementType.METHOD
})
public @interface Report {
	int type() default 0;
	String value() default "";
}

1.1.1.2 @Retention 註解

@Retention 用於定義被修飾註解的生命週期:

  • RetentionPolicy.SOURCE:僅編譯期,編譯器在編譯的時候直接丟棄,比如 @Override
  • RetentionPolicy.CLASS:僅 class 檔案,該註解僅存在 class 檔案中,不會被讀取,有些工具可以處理 class 檔案,這些工具就可以讀取這個註解
  • RetentionPolicy.RUNTIME:僅執行期,在執行期可以通過程式碼讀取該註解

如果沒有 @Retention 註解,那麼註解本身的生命週期預設為 CLASS,通常自定義的註解應該都是 RUNTIME

1.1.1.3 Repeatable 註解

Repeatable 註解修飾的註解可以重複註解,比如:

@Repeatable
@Target(ElementType.TYPE`)
public @interface Report {
	int type() default 0;
	String value() default "";
}

// 重複使用
@Report(type=1)
@Report(type=2)
public class Hello {
}

1.2 處理註解

因為通常寫的程式碼並不涉及到編譯器,class 檔案中的註解也很少會用到,所以這裡處理的註解主要針對的是執行期可以被讀取的註解,也就是 Runtime 型別的註解。 如何讀取 Runtime 的註解?方法是通過 反射。 因為 Annotaion 也是 class,所有的 Annotation 都繼承自 java.lang,annotation.Annotation,使用 反射API 就可以獲取這些 Annotation。 使用 反射API 確定一個 Annotation(註解)是否存在:

  • Class.isAnnotationPresent(Class)
  • Field.isAnnotationPresent(Class)
  • Method.isAnnotationPresent(Class)
  • Constructor.isAnnotationPresent(Class)

eg:

Class cls = Person.class;
// 判斷 @Report 是否存在
cls.isAnnotationPresent(Report.class); // 返回布林值

使用 反射API 獲取一個 Annotation(註解):

  • Class.getAnnotation(Class)
  • Field.getAnnotation(Class)
  • Method.getAnnotation(Class)
  • Constructor.getAnnotation(Class)

eg:

class cls = Person.class;
Report report = cls.getAnnotion(Report.class); // 如果不存在,返回 null
int type = report.type();

詳情通過反射讀取註解,處理註解的程式碼,可以檢視我的github

獲取方法引數的 Annotation 比較麻煩,因為一般的方法可能有多個引數,同時引數本身也可以有多個註解,此時使用的是 Method.getParemterAnnotations() 方法獲取一個 Anntation 的二維陣列,第一個維度代表的是引數的個數,第二個維度代表的是每個引數本身自帶的註解個數。