Java注解詳解

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

1. 注解是什么

之前看到一篇文章將注解理解為“標(biāo)簽”,感覺還是比較貼切的摄职。我們可以把注解理解為給包吊档、類簇爆、方法镀琉、字段打的一個(gè)標(biāo)簽,并利用java的反射機(jī)制對(duì)注解標(biāo)注的類翘地、方法或者字段進(jìn)行相應(yīng)的處理申尤。

2. 定義注解

import java.lang.annotation.*;

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

利用關(guān)鍵字@interface聲明一個(gè)注解類型癌幕,并利用@Retention、@Target昧穿、@Document勺远、@Inherited等元注解對(duì)注解進(jìn)行定義。

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

    /**
     * 會(huì)被編譯到生成的class文件中初坠,但不會(huì)在運(yùn)行時(shí)保留
     */
    CLASS,

    /**
     * 運(yùn)行時(shí)有效,可以通過反射機(jī)制讀取到該注解定義
     */
    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
    這個(gè)元注解比較簡單,用于將該注解包含在Javadoc中
  • @Inherited
    在定義注解時(shí)加上@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子類自動(dòng)被@AnnotationDemo修飾,
 *
 */
public class Child extends Super {
    public void say(){
        System.out.println("I am child!");
    }
}

3. 注解的屬性

在自定義注解時(shí)可以為注解定義若干屬性悍手,如在上邊定義的@AnnotationDemo注解中定義了一個(gè)名為name的屬性帘睦,默認(rèn)值為""袍患。注解類型只有屬性沒有方法,且注解屬性聲明為屬性名+()竣付,屬性類型可以為基本類型诡延、String、Class古胆、Enum等類型肆良。注解的屬性使用default關(guān)鍵字聲明該屬性的默認(rèn)值,如果不為屬性聲明默認(rèn)值逸绎,則必須在使用注解時(shí)為該屬性賦值惹恃。
特殊的:如果屬性名為value棺牧,在使用注解時(shí)可以不指定屬性名賦值。

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

如果注解定義了多個(gè)屬性,使用時(shí)不同的屬性賦值用逗號(hào)分隔亥鸠。

4. 注解與反射

正如在本文開頭所說的注解相當(dāng)于給類、方法家妆、字段打的標(biāo)簽伤极,對(duì)于運(yùn)行時(shí)有效的注解需要通過JDK提供的反射機(jī)制來讓標(biāo)簽起作用哨坪。下面通過一個(gè)簡單的例子來演示如何利用反射機(jī)制使注解起作用徒溪。

  • 自定義一個(gè)注解@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對(duì)@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();
        }
    }
}

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

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叔收,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蓝晒,更是在濱河造成了極大的恐慌胚嘲,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垒迂,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)她混,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旺拉,“玉大人产上,你說我怎么就攤上這事《旯罚” “怎么了晋涣?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沉桌。 經(jīng)常有香客問我谢鹊,道長,這世上最難降的妖魔是什么留凭? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任佃扼,我火速辦了婚禮,結(jié)果婚禮上蔼夜,老公的妹妹穿的比我還像新娘兼耀。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布瘤运。 她就那樣靜靜地躺著窍霞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拯坟。 梳的紋絲不亂的頭發(fā)上但金,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音郁季,去河邊找鬼冷溃。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梦裂,可吹牛的內(nèi)容都是我干的似枕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼塞琼,長吁一口氣:“原來是場噩夢啊……” “哼菠净!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起彪杉,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤毅往,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后派近,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攀唯,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年渴丸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侯嘀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谱轨,死狀恐怖戒幔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情土童,我是刑警寧澤诗茎,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站献汗,受9級(jí)特大地震影響敢订,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜罢吃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一楚午、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尿招,春花似錦矾柜、人聲如沸阱驾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啊易。三九已至,卻和暖如春饮睬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背篮奄。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工捆愁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窟却。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓昼丑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夸赫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子菩帝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容