Java注解學習


一、注解定義

JVM5.0定義了4個標准的元注解:

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

1. @Target

作用:用於描述注解的使用范圍
取值ElementType有:

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

舉例:

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

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

}

注解Table可以用於注解類、接口(包括注解類型)或enum聲明,而注解NoDBColumn僅用於注解類的成員變量。

2. @Retention

作用:用於描述注解的生命周期
取值RetentionPolicy有:

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

舉例:

@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,這樣注解處理器可以通過反射,獲取到該注解的屬性值,從而去做一些運行時的邏輯處理

3. Documented

作用:用於描述其它類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標記注解,沒有成員。

舉例:

@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的子類。

注意: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類型
  • 以上所有類型的數組

自定義注解的定義和具體實現可以見下一章節。

二、注解實現

創建注解處理器,利用反射對注解加以處理。

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<?extends Annotation> 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 供應商名稱:紅富士集團 供應商地址:紅富士大廈

三、注解基礎知識點匯總

注解基礎知識點匯總

四、參考博客

  1. 深入理解Java:注解
  2. Java技術之反射
  3. Java技術之注解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM