Java註解學習

簡介

Java註解是JDK1.5引入的一種註釋機制,它不會改變編譯器的編譯方式,Java編譯器對包含註解和不包含註解的代碼會生成相同的Java虛擬機指令。在實際應用中,註解只是一種標識,具體的操做須要藉助其餘工具來解析和處理java

註解語法

註解是使用@interface來定義的,全部註解都隱式的擴展自java.lang.annotation.Annotation接口。數組

以下MyFirstAnnotation是一個自定義註解,它具備兩個參數name和value,默認值都爲空字符串。在它的定義之上還標註了@Retention和@Target兩個元註解:函數

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
    String name() default "";

    String value() default "";
}

註解參數類型是有限制的,必須限制在如下幾種類型中:工具

  1. 基本類型
  2. String
  3. Class
  4. enum類型
  5. 註解類型
  6. 由前面所述類型組成的數組

例如,若是不使用以上幾種,則會出現編譯錯誤:測試

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
    String name() default "";

    Integer value() default 1;//包裝類型也不行,編譯錯誤
}

@Target和@Retention這種做用在註解上的註解,稱之爲元註解。經常使用的元註解以下:code

1.@Target,用於標識註解能夠標註的位置,接收一個ElementType[]參數。參數取值能夠參考ElementType枚舉類:繼承

public enum ElementType {
    /** 類、接口(包括註釋類型)或枚舉聲明 */
    TYPE,

    /** 字段聲明(包括enum常量) */
    FIELD,

    /** 方法聲明 */
    METHOD,

    /** 形參聲明 */
    PARAMETER,

    /** 構造函數聲明 */
    CONSTRUCTOR,

    /** 局部變量聲明 */
    LOCAL_VARIABLE,

    /** 註解類型聲明 */
    ANNOTATION_TYPE,

    /** 包聲明 */
    PACKAGE,

    /**
     * 類型參數聲明
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 任何類型名稱
     *
     * @since 1.8
     */
    TYPE_USE
}

當指定的@Target和註解的使用位置不匹配時就會出現編譯錯誤,以下所示,@Target(ElementType.METHOD)表示MyFirstAnnotation註解只能用來標註方法,標註在類上就出現編譯錯誤:接口

//編譯錯誤
@MyFirstAnnotation
public class Demo {

    //正確
    @MyFirstAnnotation
    public void doSomeThing(){
    }

}

2.@Retention,用於標識註解能夠保留多久,接收一個RetentionPolicy參數,參數取值能夠參考RetentionPolicy枚舉類:字符串

public enum RetentionPolicy {
    /**
     * 表示註解只會存在於.java的源代碼文件中,不會保留到編譯後的.class文件中
     */
    SOURCE,

    /**
     * 表示註解能夠保留到.class文件中,可是不會被Java虛擬機所加載
     */
    CLASS,

    /**
     * 表示註解能夠保留到.class文件中,並由虛擬機加載
     */
    RUNTIME
}

3.@Documented,表示這個註解能出如今javadoc中。get

4.@Inherited,表示當這個註解用於一個類的時候,可以自動的被它的子類繼承。

5.@Repeatable,表示這個註解能夠在同一個位置應用屢次。

默認狀況下,同一個位置添加多個重複註解會有編譯錯誤:

public class Demo {
    //編譯錯誤
    @MyFirstAnnotation(name = "張三")
    @MyFirstAnnotation(name = "李四")
    @MyFirstAnnotation(name = "王五")
    public void doSomeThing(){
    }

}

能夠經過添加@Repeatable元註解來使@MyFirstAnnotation能重複使用。
首先須要建立一個容器註解@MyFirstAnnotations,容器註解@MyFirstAnnotations必需要有一個參數value,而且其類型爲MyFirstAnnotation[]:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotations {
    MyFirstAnnotation[] value();
}

而後添加@Repeatable註解,並指定容器註解。

@Repeatable(MyFirstAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFirstAnnotation {
    String name() default "";

    String value() default "";
}

關於註解的使用須要注意,註解參數是不能爲null的,默認值也是不能爲null

自定義註解測試

定義註解@RepeatMethod,包含int類型參數value。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatMethod {

    int value() default 1;

}

在doSomeThing方法上應用註解。若是要指定的註解參數爲value,而且沒有指定其餘的參數值時,能夠採用簡寫的方式,省略參數名和等號。

public class Demo {
    @RepeatMethod(5)
    public void doSomeThing(){
        System.out.println("----註解測試----");
    }
}

經過反射獲取註解信息,而後作對應的處理,如假設@RepeatMethod註解的做用是重複調用被標註的方法,參數value是指定重複調用方法的次數:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyDemo {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        Class cla = Demo.class;
        Method[] methods = cla.getMethods();
        Object demo = cla.newInstance();
        for (Method method : methods){
            //判斷方法上是否有標註@RepeatMethod註解
            if(method.isAnnotationPresent(RepeatMethod.class)){
                //獲取RepeatMethod註解的參數值
                RepeatMethod repeatMethod = method.getAnnotation(RepeatMethod.class);
                for (int i = 0;i < repeatMethod.value(); i++)
                method.invoke(demo, null);
            }
        }
    }
}

輸出結果:

----註解測試----
----註解測試----
----註解測試----
----註解測試----
----註解測試----
相關文章
相關標籤/搜索