Java註解學習

1、註解定義

JVM5.0定義了4個標準的元註解:html

  • @Target,
  • @Retention,
  • @Documented
  • @Inherited

1. @Target

做用:用於描述註解的使用範圍
取值ElementType有:java

  • CONSTRUCTOR:用於描述構造器
  • FIELD:用於描述域
  • LOCAL_VARIABLE:用於描述局部變量
  • METHOD:用於描述方法
  • PACKAGE:用於描述包
  • PARAMETER:用於描述參數
  • TYPE:用於描述類、接口(包括註解類型) 或enum聲明

舉例:api

@Target(ElementType.TYPE)
public @interface Table {
    /**
     * 數據表名稱註解,默認值爲類名稱
     * @return
     */
    public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {

}

註解Table能夠用於註解類、接口(包括註解類型)或enum聲明,而註解NoDBColumn僅用於註解類的成員變量。數組

2. @Retention

做用:用於描述註解的生命週期
取值RetentionPolicy有:oracle

  • SOURCE:在源文件中有效(即源文件保留)
  • CLASS:在class文件中有效(即class保留)
  • RUNTIME:在運行時有效(即運行時保留)

舉例:app

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}

Column註解的的RetentionPolicy的屬性值是RUNTIME,這樣註解處理器能夠經過反射,獲取到該註解的屬性值,從而去作一些運行時的邏輯處理ide

3. Documented

做用:用於描述其它類型的annotation應該被做爲被標註的程序成員的公共API,所以能夠被例如javadoc此類的工具文檔化。Documented是一個標記註解,沒有成員。工具

舉例:ui

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}

4. @Inherited

@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。若是一個使用了Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。this

注意:Inherited annotation類型是被標註過的class的子類所繼承。類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼承annotation。

當Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。若是咱們使用java.lang.reflect去查詢一個Inherited annotation類型的annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層

實例代碼:

@Inherited
public @interface Greeting {
    public enum FontColor{ BULE,RED,GREEN};
    String name();
    FontColor fontColor() default FontColor.GREEN;
}

5. 自定義註解

  • 使用interface自定義註解,自動繼承java.lang.annotation.Annotation接口。
  • 不能繼承其餘的註解或接口。
  • 每個方法其實是聲明瞭一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(只能是基本類型、Class、String、enum)。能夠經過default聲明參數的默認值。

定義註解格式:

public @interface 註解名(定義體)

註解參數的可支持數據類型:

  • 全部基本數據類型(int,float,boolean,byte,double,char,long,short)
  • String類型
  • Class類型
  • enum類型
  • Annotation類型
  • 以上全部類型的數組

自定義註解的定義和具體實現能夠見下一章節。

2、註解實現

建立註解處理器,利用反射對註解加以處理。

AnnotatedElement 接口是全部程序元素(Class、Method和Constructor)的父接口,關於AnnotatedElement點詳細信息能夠參考

JavaDoc:Interface AnnotatedElement

因此程序經過反射獲取了某個類的AnnotatedElement對象以後,程序就能夠調用該對象的以下四個個方法來訪問Annotation信息:

  • 方法1:
<T extends Annotation> T getAnnotation(Class<T> annotationClass):

返回改程序元素上存在的、指定類型的註解,若是該類型註解不存在,則返回null。

  • 方法2:Annotation[] getAnnotations():返回該程序元素上存在的全部註解。

  • 方法3:boolean is AnnotationPresent(Class annotationClass):判斷該程序元素上是否包含指定類型的註解,存在則返回true,不然返回false.

  • 方法4:Annotation[] getDeclaredAnnotations():返回直接存在於此元素上的全部註釋。與此接口中的其餘方法不一樣,該方法將忽略繼承的註釋。(若是沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)該方法的調用者能夠隨意修改返回的數組;這不會對其餘調用者返回的數組產生任何影響。

舉例:

註解聲明

1.FruitName

package annotation;

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

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}

2.FruitColor

package annotation;

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

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    public enum Color{BlUE, RED, GREEN};
    Color fruitColor() default Color.GREEN;

}

3.FruitProvider

package annotation;

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

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    public int id() default -1;
    public String name() default "";
    public String address() default "";
}

註解使用

package annotation;

import annotation.FruitColor.Color;

public class Apple {
    @FruitName("Apple")
    private String appleName;
    
    @FruitColor(fruitColor=Color.RED)
    private String appleColor;

    @FruitProvider(id=1, name="紅富士集團", address="紅富士大廈")
    private String appleProvider;

    public String getAppleName() {
        return appleName;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }

    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }
    
    public String getAppleProvider() {
        return appleProvider;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }
    
    public void display(){
        System.out.println("The fruit name is:" + appleName + ", its color is: " + appleColor + ".");
    }
    
}

註解實現

package annotation;

import java.lang.reflect.Field;

public class FruitInfoUtil {
    public static void getFruitInfo(Class<?> clazz){
        String strFruitName= "水果名稱: ";
        String strFruitColor= "水果顏色: ";
        String strFruitProvider= "供應商信息: ";
        
        Field[] fields = clazz.getDeclaredFields();
        
        for(Field field : fields){
            if (field.isAnnotationPresent(FruitName.class)){
                FruitName fruitName = (FruitName)field.getAnnotation(FruitName.class);
                strFruitName += fruitName.value();
                System.out.println(strFruitName);
            }
            
            
            if (field.isAnnotationPresent(FruitColor.class)){
                FruitColor fruitColor = (FruitColor)field.getAnnotation(FruitColor.class);
                strFruitColor += fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);
            }
            
            if (field.isAnnotationPresent(FruitProvider.class)){
                FruitProvider fruitProvider = (FruitProvider)field.getAnnotation(FruitProvider.class);
                strFruitProvider += " 供應商編號:" + fruitProvider.id() + " 供應商名稱:" + fruitProvider.name() + " 供應商地址:" + fruitProvider.address();
                System.out.println(strFruitProvider);
            }
        }
    }
}

執行結果:

水果名稱: Apple
水果顏色: RED
供應商信息:  供應商編號:1 供應商名稱:紅富士集團 供應商地址:紅富士大廈

3、註解基礎知識點彙總

註解基礎知識點彙總

4、參考博客

  1. 深刻理解Java:註解
  2. Java技術之反射
  3. Java技術之註解
相關文章
相關標籤/搜索