Java注解詳解

雖然在平時開發(fā)中經(jīng)常使用注解,卻不知道如何自定義一個注解類型以及注解的實現(xiàn)原理。抽時間學(xué)習(xí)了一下,記錄下來加深理解。

1. 注解是什么

之前看到一篇文章將注解理解為“標(biāo)簽”,感覺還是比較貼切的。我們可以把注解理解為給包、類、方法、字段打的一個標(biāo)簽,并利用java的反射機制對注解標(biāo)注的類、方法或者字段進行相應(yīng)的處理。

2. 定義注解

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String name() default "";
}

利用關(guān)鍵字@interface聲明一個注解類型,并利用@Retention、@Target、@Document、@Inherited等元注解對注解進行定義。

  • @Retention
    用于自定義注解類型的元注解。retention的意思是保留,@Retention用來定義自定義注解有效期。有三種取值:
public enum RetentionPolicy {
    /**
     * 注解只在源碼文件中保留,不會被編譯器編譯
     */
    SOURCE,

    /**
     * 會被編譯到生成的class文件中,但不會在運行時保留
     */
    CLASS,

    /**
     * 運行時有效,可以通過反射機制讀取到該注解定義
     */
    RUNTIME
}
  • @Target
    用于定義注解的使用目標(biāo)。我們知道注解可以用在包、類、方法、字段等字面量上,但不能將類的注解用到方法上,JDK使用@Target定義注解的使用目標(biāo)。在java.lang.annotation.ElementType 枚舉類型中定義了若干注解目標(biāo)枚舉常量:TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE等。
    ElementType.TYPE 用于定義類、接口、枚舉注解;
    ElementType.METHOD 用于定義方法注解;
    ElementType.FIELD 用于定義字段注解;
    ElementType.CONSTRUCTOR 用于定義構(gòu)造器注解;
  • @Document
    這個元注解比較簡單,用于將該注解包含在Javadoc中
  • @Inherited
    在定義注解時加上@Inherited表示該注解具有"繼承性",這里的繼承性是指如果父類使用了自定義注解,則子類也繼承了該自定義注解。舉例說明:
/**
 * 自定義注解AnnotationDemo、使用@Inherited表明該注解注解具有繼承性
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String name() default "";
}
/**
 * 使用自定義注解修飾的父類
 */
@AnnotationDemo(name = "小明")
public class Super {
    public void hello(){
        System.out.println("I am super!");
    }
}
/**
 * 子類繼承Super超類
 * 由于Super被@AnnotationDemo注解修飾,Child子類自動被@AnnotationDemo修飾,
 *
 */
public class Child extends Super {
    public void say(){
        System.out.println("I am child!");
    }
}

3. 注解的屬性

在自定義注解時可以為注解定義若干屬性,如在上邊定義的@AnnotationDemo注解中定義了一個名為name的屬性,默認(rèn)值為""。注解類型只有屬性沒有方法,且注解屬性聲明為屬性名+(),屬性類型可以為基本類型、String、Class、Enum等類型。注解的屬性使用default關(guān)鍵字聲明該屬性的默認(rèn)值,如果不為屬性聲明默認(rèn)值,則必須在使用注解時為該屬性賦值。
特殊的:如果屬性名為value,在使用注解時可以不指定屬性名賦值。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationDemo {
    String value() default "";
}
/**
 * @AnnotationDemo注解的屬性名為value,使用時可以不指定屬性名為屬性賦值
 * 等價于@AnnotationDemo(value="super")
 */
@AnnotationDemo("super")
public class Super {
    public void hello(){
        System.out.println("hello world!");
    }
}

如果注解定義了多個屬性,使用時不同的屬性賦值用逗號分隔。

4. 注解與反射

正如在本文開頭所說的注解相當(dāng)于給類、方法、字段打的標(biāo)簽,對于運行時有效的注解需要通過JDK提供的反射機制來讓標(biāo)簽起作用。下面通過一個簡單的例子來演示如何利用反射機制使注解起作用。

  • 自定義一個注解@Run
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Run {
    
}
  • 使用定義的注解標(biāo)注方法
public class RunTest {
    @Run
    public void test1(){
        System.out.println("run test1");
    }

    public void test2(){
        System.out.println("run test2");
    }
}
  • 通過反射API對@Run標(biāo)記的方法執(zhí)行調(diào)用
public class Main {

    public static void main(String[] args) throws ClassNotFoundException{
        try {
            Class clazz = Class.forName("com.annotation.demo.test.RunTest");
            Method[] methods = clazz.getMethods();
            RunTest junitTest =(RunTest) clazz.newInstance();
            for (Method method : methods){
                if (method.isAnnotationPresent(Run.class)){
                    method.setAccessible(true);
                    method.invoke(junitTest);
                }
            }
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }catch (InstantiationException e){
            e.printStackTrace();
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }catch (InvocationTargetException e){
            e.printStackTrace();
        }
    }
}

在這個例子中首先定義了一個@Run注解,并在RunTest中定義了兩個方法。其中一個方法使用了@Run進行注解,另一個方法沒有添加@Run注解,利用反射API對使用了@Run注解的方法進行調(diào)用。輸出結(jié)果也正如我們所料:只有RunTest中的test1方法被執(zhí)行。

OK,java注解的介紹就到這里。

你的關(guān)注是我持續(xù)更新的動力!

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

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

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