Java Annotation注解

1 Java 元注解

元注解的作用就是負(fù)責(zé)注解其他注解。Java5.0定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類(lèi)型,它們被用來(lái)提供對(duì)其它 annotation類(lèi)型作說(shuō)明。Java5.0定義的元注解:

  • 1.@Target,
  • 2.@Retention,
  • 3.@Documented,
  • 4.@Inherited

這些類(lèi)型和它們所支持的類(lèi)在java.lang.annotation包中可以找到。下面我們看一下每個(gè)元注解的作用和相應(yīng)分參數(shù)的使用說(shuō)明。

@Target

@Target說(shuō)明了Annotation所修飾的對(duì)象范圍,默認(rèn)可以使用在任何地方:

用法 使用范圍
@Target(ElementType.METHOD) 用于方法
@Target(ElementType.TYPE) 用于類(lèi)或者接口
@Target(ElementType.ANNOTATION_TYPE) 用于注解類(lèi)型(被@interface修飾的類(lèi)型)
@Target(ElementType.CONSTRUCTOR) 用于構(gòu)造方法
@Target(ElementType.FIELD) 用于域
@Target(ElementType.LOCAL_VARIABLE) 用于局部變量
@Target(ElementType.PACKAGE) 記錄java文件的package信息
@Target(ElementType.PARAMETER) 用于參數(shù)

在Annotation類(lèi)型的聲明中使用了target可更加明晰其修飾的目標(biāo)。

@Retention

@Retention定義了該Annotation被保留的時(shí)間長(zhǎng)短:某些Annotation僅出現(xiàn)在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會(huì)被虛擬機(jī)忽略,而另一些在class被裝載時(shí)將被讀取(請(qǐng)注意并不影響class的執(zhí)行,因?yàn)锳nnotation與class在使用上是被分離的)。使用這個(gè)meta-Annotation可以對(duì) Annotation的“生命周期”限制。

作用:表示需要在什么級(jí)別保存該注釋信息,用于描述注解的生命周期(即:被描述的注解在什么范圍內(nèi)有效)

取值(RetentionPoicy)有:

取值 有效范圍
@Retention(RetentionPolicy.SOURCE) 在源文件中有效(即源文件保留)
@Retention(RetentionPolicy.CLASS) 在class文件中有效(即class保留)
@Retention(RetentionPolicy.RUNTIME) 在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)

Column注解的的RetentionPolicy的屬性值是RUTIME,這樣注解處理器可以通過(guò)反射,獲取到該注解的屬性值,從而去做一些運(yùn)行時(shí)的邏輯處理。

@Documented

@Documented用于描述其它類(lèi)型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類(lèi)的工具文檔化。Documented是一個(gè)標(biāo)記注解,沒(méi)有成員。

@Inherited

@Inherited 元注解是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類(lèi)型是被繼承的。如果一個(gè)使用了@Inherited修飾的annotation類(lèi)型被用于一個(gè)class,則這個(gè)annotation將被用于該class的子類(lèi)。

注意:@Inherited annotation類(lèi)型是被標(biāo)注過(guò)的class的子類(lèi)所繼承。類(lèi)并不從它所實(shí)現(xiàn)的接口繼承annotation,方法并不從它所重載的方法繼承annotation。

當(dāng)@Inherited annotation類(lèi)型標(biāo)注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強(qiáng)了這種繼承性。如果我們使用java.lang.reflect去查詢(xún)一個(gè)@Inherited annotation類(lèi)型的annotation時(shí),反射代碼檢查將展開(kāi)工作:檢查class和其父類(lèi),直到發(fā)現(xiàn)指定的annotation類(lèi)型被發(fā)現(xiàn),或者到達(dá)類(lèi)繼承結(jié)構(gòu)的頂層。

自定義注解

下面寫(xiě)一個(gè)從*.properties文件中讀取配置,來(lái)演示如何開(kāi)發(fā)一個(gè)自定義注解。

我們需要定義兩個(gè)注解,第一個(gè)用來(lái)從路徑中讀取配置文件*.properties定義為@Source,第二個(gè)用來(lái)給變量賦值,定義為@Value。

Source.java

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

@Retention(RetentionPolicy.RUNTIME) //在運(yùn)行時(shí)有效
@Target(ElementType.TYPE) //用于類(lèi)或者接口
public @interface Source {
  String value() default "src/main/resources/*.properties";
}

Value.java

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

@Retention(RetentionPolicy.RUNTIME)//在運(yùn)行時(shí)有效
@Target(ElementType.FIELD)//用于域
public @interface Value {
  String value();
}

下面演示如何工作。

test-annotation.properties

hello=annotation

TestAnnotation.java

//使用@Source標(biāo)記配置文件來(lái)源
@Source(value = "src/main/resources/test-annotation.properties")
public class TestAnnotation {
    //使用@Value標(biāo)記讀取的屬性
    @Value(value = "hello")
    public static String hello;


    public static void main(String[] args) {
        AnnotationWork.work(TestAnnotation.class);

        System.out.println(hello);
    }
}

結(jié)果為

annotation

重點(diǎn)就在于AnnotationWork.load(TestAnnotation.class);這行。

AnnotationWork.java

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Properties;

public class AnnotationWork {
    public static void work(Class clazz){
        if(clazz.isAnnotationPresent(Source.class)){//判斷class是否有@Source注解
            String propertiesSource = ((Source) clazz.getAnnotation(Source.class)).value();
            try {
                Properties properties = new Properties();
                properties.load(new FileReader(propertiesSource));
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if(field.isAnnotationPresent(Value.class)) {//判斷屬性屬否有@Value注解
                        String fieldKey = field.getAnnotation(Value.class).value();
                        field.set(clazz.newInstance(), properties.get(fieldKey));
                    }
                }
            }catch (IOException | IllegalAccessException | InstantiationException e){
                e.printStackTrace();
            } 
        }
    }
}

代碼用反射的方法給hello賦予了初始值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容