天天看點

Java注解分析以及自定義注解

注解對于開發人員來講既熟悉又陌生,熟悉是因為隻要你是做開發,都會用到注解(常見的@Override);陌生是因為即使不使用注解也照常能夠進行開發;注解不是必須的,但了解注解有助于我們深入了解某些第三方架構(比如Spring,Hibernate,Mybatis等),提高工作效率。

Java注解又稱為标注,是Java從1.5開始支援加入源碼的特殊文法中繼資料;Java中的類、方法、變量、參數、包都可以被注解。這裡提到的中繼資料是描述資料的資料

1. 注解作用

格式檢查:      告訴編譯器資訊,比如被@Override标記的方法如果不是父類的某個方法,IDE會報錯;

減少配置:      運作時動态處理,得到注解資訊,實作代替配置檔案的功能;

減少重複工作:比如第三方架構xUtils,通過注解@ViewInject減少對findViewById的調用,

                        類似的還有(JUnit、ActiveAndroid等);

2. 注解分三類

1:JDK自帶的注解(Java目前隻内置了三種标準注解:@Override、@Deprecated、@SuppressWarnings,以及四種元注解:@Target、@Retention、@Documented、@Inherited)

2:第三方的注解——這一類注解是我們接觸最多和作用最大的一類

3:自定義注解——也可以看作是我們編寫的注解,其他的都是他人編寫注解

3. 自定義注解

JVM5.0定義了4個标準的元注解:

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

    3.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僅用于注解類的成員變量。   

    3.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.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;
}
           

    3.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;
}
           

    3.5 自定義注解

    1. 使用interface自定義注解,自動繼承java.lang.annotation.Annotation接口。

    2. 不能繼承其他的注解或接口。

    3. 每一個方法實際上是聲明了一個配置參數。方法的名稱就是參數的名稱,傳回值類型就是參數的類型(隻能是基本類型、Class、String、enum)。可以通過default聲明參數的預設值。

    定義注解格式:

    public @interface 注解名(定義體)

    注解參數的可支援資料類型:

    所有基本資料類型(int,float,boolean,byte,double,char,long,short)

        1. String類型

        2. Class類型

        3. enum類型

        4.Annotation類型

    以上所有類型的數組

    3.6  代碼實踐

    注解類代碼

@Retention(RetentionPolicy.RUNTIME) // 注解會在class位元組碼檔案中存在,在運作時可以通過反射擷取到  
@Target({ElementType.FIELD,ElementType.METHOD})//定義注解的作用目标**作用範圍字段、枚舉的常量/方法  
@Documented//說明該注解将被包含在javadoc中 
public @interface FieldAnnotation {
	String name() default "哈哈";
}
           

    業務類

public class Student {
	@FieldAnnotation(name="牛逼")
	private String name;
	private String id;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}
           

測試類

public class StudentTest {

	public static void main(String[] args) {
		Field[] declaredFields = Student.class.getDeclaredFields();
	    for (Field f : declaredFields) {
	    	System.out.println(f.isAnnotationPresent(FieldAnnotation.class));
	    	if (f.isAnnotationPresent(FieldAnnotation.class)) {
	    		//獲得注解的對象
	    		FieldAnnotation fa = f.getAnnotation(FieldAnnotation.class);
	    		if (fa != null) {
	    			System.out.println(fa.name());
	    		}
	    	}
	    }
	}
}