淺談Java中的註解

註解概述

註解即Annotation是JDK5.0開始引入的新技術。
作用

  • 註解不是程序本身,但是可以對程序作出解釋。這一點的功能類似於註釋(comment)。
  • 註解可以被其他程序讀取,如編譯器。

格式: 註解 是以 “@註釋名” 的形式在程序中存在的,還可以添加一些參數。例如:@SuppressWarnings(value=“unchecked”)。

使用範圍
註解可以附加在package、class、method、field等上面,這相當於給他們添加了額外的輔助信息。我們可以通過反射機制編程實現對這些元數據的訪問。

分類

  • 內置註解
  • 元註解
  • 自定義註解

內置註解

內置註解是註解的一種。我們遇到的 @Override、@Deprecated、@SuppressWarnings 都是內置註解。

當我們在進行方法的重寫的時候,會遇到方法的上一行是 “@Override”,@Override 就是一個內置註解,它是定義在java.lang.Override中的,該註解只適用於修飾方法,表明一個方法聲明打算重寫超類(父類)的另一個方法聲明。

在調用一個類的方法時,有時會遇到"@Deprecated",@Deprecated是定義java.lang.Deprecated 中的,該註解可以用於修飾方法、屬性、類,表示不鼓勵程序員使用這樣的元素,通常是因爲它很危險或者存在更好的選擇。對於由"@Deprecated"修飾的元素,java中是不建議使用的,但是是可以使用的。

@SuppressWarnings,定義在java.lang.SuppressWarnings中,用於一直編譯時的警告信息。但與上面的註解不同的是,需要添加一個參數纔可以正確使用該註解,這些參數是java定義好的,我們只要選擇性地去使用就行。如下:

@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings(value={"unchecked","deprecation"})

元註解

元註解是註解的一個分類,它的作用是負責註解其他註解,java中定義了四個標準的meta-annotation類型,它們被用來提供對其他annotation類型作說明。
這些類型和它們所支持的類在java.lang.annotation包中可以找到。
分類

  • @Target:用於描述註解的使用範圍即被描述的註解可以用在什麼地方。
  • @Retention:表示需要在什麼級別保存該註解信息,用於描述註解的生命週期。
  • @Documented:說明該註解將被包含在javadoc中。
  • @Inherited:說明子類可以繼承父類中的該註解。

@Target

@Target:用於描述註解的使用範圍即被描述的註解可以用在什麼地方。
@Target源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

ElementType源碼:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

根據源碼可以知道,@Target註解的使用範圍:

名稱 使用範圍
TYPE 類,接口(包括註解類型)以及枚舉
FIELD 字段(包括枚舉常量)
METHOD 方法
PARAMETER 參數
CONSTRUCTOR 構造方法
LOCAL_VARIABLE 局部變量
ANNOTATION_TYPE 註解類型
PACKAGE
TYPE_PARAMETER(JDK1.8開始) 類型參數
TYPE_USE(JDK1.8開始) 類型的使用

@Retention

@Retention:表示需要在什麼級別保存該註解信息,用於描述註解的生命週期。
@Retention源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

RetentionPolicy源碼:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

根據源碼可以知道 @Retention使用的生命週期有三個:

  • SOURCE:註解將被編譯器丟棄
  • CLASS:註解由編譯器記錄在類文件中,但虛擬機在運行時無需保留。 這是默認行爲。
  • RUNTIME:註解由編譯器記錄在類文件中,並在運行時由VM保留,因此可以通過反射方式讀取它們。

上面的三個生命週期是 SOURCE < CLASS < RUNTIME.

@Documented

@Documented:說明該註解將被包含在javadoc中。
@Documented 源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited

@Inherited:說明子類可以繼承父類中的該註解。
@Inherited源碼:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

自定義註解

除了java給我們提供的內置註解之外,我們還可以自己定義註解,即自定義註解。
格式

public @interface  註解名 {
		定義內容
}

在使用 @interface 自定義註解時,會自動繼承java.lang.annotation.Annotation接口。

分析

  • @interface 用來聲明一個註解
  • 定義的註解中的每一個方法實際上是聲明瞭一個配置參數
  • 方法的名稱就是參數的名稱
  • 返回值類型就是參數的類型,返回值類型只能是基本類型、Class、String、enum
  • 可以通過default來聲明參數的默認值
  • 如果只有一個參數成員,一般參數名爲value
  • 註解元素必須要有值,在定義註解元素時,經常食用空字符串、0作爲默認值。

自定義註解舉例:

public class Test01 {
    public static void main(String[] args) {
        test();
    }

    @MyAnnotation("ll")   
    public static void test(){
        System.out.println("This is my annotation");
    }

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value();   //  只有一個參數成員時,一般參數名爲value
}

上述例子中,自定義註解的參數只有一個,所以將參數名命名爲value,且在寫 @MyAnnotation(“ll”) 註解的時候,可以將參數名省去即將"value="省略不寫,但是當註解中的參數大於等於兩個時,就必須加上參數名。如下:

public class Test01 {
    public static void main(String[] args) {
        test();
    }

    @MyAnnotation(value = "ll",num = 1)
    public static void test(){
        System.out.println("This is my annotation");
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value();
    int num();
}

自定義註解中,默認值的使用:

public class Test01 {
    public static void main(String[] args) {
        test();
    }

    @MyAnnotation(value = "ll")
    public static void test(){
        System.out.println("This is my annotation");
    }

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value();
    int num() default 0;
}

當參數有默認值的時候,在寫註解時該參數可以傳遞參數也可以不傳遞參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章