java註解(1)

參考:java

  1. 秒懂,Java 註解 (Annotation)你能夠這樣學
  2. 瘋狂java講義

1. 定義

classsinterface 同樣,註解也屬於一種類型。
註解經過 @interface 關鍵字進行定義。數組

public @interface TestAnnotation {
}

2. 語法

默認狀況下,Annotation可用於修飾任何程序元素,包括接口、類、方法等。app

Annotation成員變量以方法形式定義

Annotation中的成員變量以無形參的方法形式來聲明。定義了幾個成員變量,在使用時必須給值。ide

public @interface MyTag {
    String name();
    int age();
}

有個默認值,在使用時能夠不給值。工具

public @interface MyTag {
    String name() default "hobe";
    int age() default 18;
}

Annotation

jdk除了java.lang下的5個基本Annotation:.net

  • @Override(限定重寫)
  • @Deprecated(標記過期)
  • @SuppressWarnings(抑制警告)
  • @SafeVarargs(java7)
  • @functionalInterface(java8)

以外,java.lang.annotation包下提供了6個Meta Annotation(元Annotation),其中5個都用於修飾其餘Annotation。主要幾個以下:code

1 @Retention

只能修飾Annotation定義,指定修飾多長時間,其源碼:orm

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

其中只有一個成員變量。blog

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
}

SOURCE:用於檢查代碼,編譯時丟掉。(主要看IDE是否報錯)
CLASS:(默認)。編譯後也會記錄在class文件中。運行時,JVM不可獲取Annotation信息,不可反射獲取。
RUNTIME:(一般會使用)。編譯後也會記錄在class文件中。運行時,JVM可獲取Annotation信息,可反射獲取接口

使用示例

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
    ...
}

或:

@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    ...
}

說明

當Annotation成員變量名爲 value時,只需爲value指定值時, 能夠在括號裏直接寫出value的值,無需name=value的形式

2 @Target

只能修飾Annotation定義。指定哪些程序單元能夠使用,源碼:

@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();
}
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({ElementType.FIELD})

3 @Documented

被該Annotation修飾的類將會被javadoc工具提取成文檔。

4 @Inherited

被@Inherited修飾的註解,用於父類時,子類自動會加該註解。

System.out.println(ChildClass.class.isAnnotationPresent(MyTag.class));

true

3. 自定義Annotation

分類:標記Annotation元數據Annotation

根據Annotation是否包含成員變量,將其分爲兩類:

  • 標記Annotation:沒有定義成員變量,盡利用自身是否存在與否來提供信息。如@Test,@Override
  • 元數據Annotation:包含成員變量。

注意的一種狀況是一個註解沒有任何屬性。好比

public @interface Perform {}

那麼在應用這個註解的時候,括號均可以省略。

@Perform
public void testMethod(){}

示例

@Target({ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    String name() default "hobe"; //字符串
    int age() default 18;  //int
    String[] likes(); // 數組
    Sex sex(); //枚舉
}

反射提取Annotation信息

使用Annotation修飾了類、方法、成員變量等成員以後,這些Annotation並不會本身生效。必須由開發者提取信息並處理。
java.lang.reflect增長了讀取運行時Annotation的能力。如:

  • getAnnotation()
  • getAnnotations()
  • isAnnotationPresent()
  • getAnnotationsByType()
  • ...

如獲取Mytag註解中info方法上的全部註解,則:

Class.forName("MyTag").getMethods("info").getAnnotations()

使用示例

  • 註解類:
@Target({ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    String name() default "hobe"; //字符串
    int age() default 18;  //int
    String[] likes(); // 數組
    Sex sex() default Sex.BOY; //枚舉
}
public enum Sex {
    BOY,GIRL
}
  • 工具類(這裏工具類和被註解類放在一塊兒了)
@MyTag(likes = {"code","ball"})
public class Demo {
    private String name;
    private Integer age;
    private String[] likes;
    private Sex sex;

    public static void main(String[] args) {
        Demo demo = new Demo();
        /** 僅僅註解,並不能將值賦給Demo的字段 */
        System.out.println(demo);

        boolean hasAnnotation = Demo.class.isAnnotationPresent(MyTag.class);
        if (hasAnnotation){
            MyTag myTag = Demo.class.getAnnotation(MyTag.class);
            System.out.println(myTag.name());
            System.out.println(myTag.likes());
            System.out.println(myTag.sex());
            System.out.println(myTag.age());
        }
    }
    ...
}

結果:

Demo{name='null', age=null, likes=null, sex=null}
hobe
[Ljava.lang.String;@4617c264
BOY
18

參考:

  1. 秒懂,Java 註解 (Annotation)你能夠這樣學
  2. 瘋狂java講義
相關文章
相關標籤/搜索