1. 程式人生 > >java @interface自定義註解和通過反射獲取註解屬性值

java @interface自定義註解和通過反射獲取註解屬性值

@interface

@interface用來宣告一個註解,其中的每一個方法實際上是聲明瞭一個配置引數。
方法的名稱就是引數的名稱,返回值型別就是引數的型別
引數型別只能是基本型別、Class、String、enum。
可以通過default來宣告引數的預設值。
Java註解就是一種特殊的介面,使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面,因此在自定義註解時不能繼承其他的註解或者介面。

註解的應用

  1. 生成文件。如@param @return 等
  2. 替代配置檔案功能。如spring2.5開始的基於註解配置。作用就是減少配置。現在的框架基本都使用了這種配置來減少配置檔案的數量
  3. 在編譯時進行格式檢查。如@Override

自定義註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProductAnnotation {

    //型別列舉
    public enum Type{ 手機,電腦,平板};
    //商品型別
    Type productType() default Type.手機;
    //商品釋出時間
    String publishYear() default "";
    //商品名稱
    String productName() default
""; }

Target 指明該型別的註解可以註解的元素範圍,主要包括以下幾種引數型別:

ElementType.TYPE 用於類,介面,列舉,但不能是註解
ElementType.FIELD 作用於欄位,包含列舉值
ElementType.METHOD 作用於方法,不包含構造方法
ElementType.PARAMETER 作用於方法的引數
ElementType.CONSTRUCTOR 作用於構造方法
ElementType.LOCAL_VERIABLE 作用於本地變數或者catch語句
ElementType.ANNOTATION_TYPE 作用於註解
ElementType.PACKAGE 作用於包

Retention 指明在什麼級別顯示此註解,主要包括以下幾種引數型別:

RetentionPolicy.SOURCE 註解存在於原始碼中,編譯時會被拋棄
RetentionPolicy.CLASS 註解會被編譯到class檔案中,但是JVM會忽略
RetentionPolicy.RUNTIME JVM會讀取註解,同時會儲存到class檔案中

通過反射獲取註解屬性值

註解的解析依賴於反射。jdk1.5 增加了註解,也增加了讀取註解的api,在java.lang.reflect包中新增了AnnotatedElement介面,JDK原始碼如下:

    public interface AnnotatedElement {  
            boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);  
            <T extends Annotation> T getAnnotation(Class<T> annotationClass);  
            Annotation[] getAnnotations();  
            Annotation[] getDeclaredAnnotations();  
    }  
isAnnotationPresent:判斷是否標註了指定註解
getAnnotation:獲取指定註解,沒有則返回null
getAnnotations:獲取所有註解,包括繼承自基類的,沒有則返回長度為0的陣列
getDeclaredAnnotations:獲取自身顯式標明的所有註解,沒有則返回長度為0的陣列

通過反射獲取註解屬性值的例子:

public class ProductReflectAnnotation {

    @ProductAnnotation(productName="iphone X",publishYear="2017釋出")
    private String iphoneX;//iponeX配上註解
    @ProductAnnotation(productType= ProductAnnotation.Type.電腦,productName="mac",publishYear="2018釋出")
    private String mac;//Mac配上註解
    private String noAnnotationField;//noAnnotationField不加註解

    public static void main(String[] args) {
        // 解析ProductReflectAnnotation類屬性的註解
        // getDeclaredFields方法會返回ProductReflectAnnotation類所有的屬性
        Field[] fields = ProductReflectAnnotation.class.getDeclaredFields();
        for(Field field : fields){
            //判斷屬性是否標註了@ProductAnnotation註解
            boolean fieldHasAnno = field.isAnnotationPresent(ProductAnnotation.class);
            if(fieldHasAnno){
                //獲取@ProductAnnotation註解
                ProductAnnotation product = field.getAnnotation(ProductAnnotation.class);
                //獲取@ProductAnnotation註解 引數值
                String name = product.productName();
                String publishYear = product.publishYear();
                ProductAnnotation.Type type = product.productType();
                System.out.println("[" + field.getName() + "] " + name + ","+ type + "," + publishYear);
            }
        }
    }

}

輸出:

[iphoneX] iphone X,手機,2017釋出
[mac] mac,電腦,2018釋出