Java語言高級特性——注解

一 注解作用或意義

  • 定義
    Java 注解(Annotation)又稱 Java 標注吞加,是 JDK5.0 引入的一種注釋機制裙犹。 注解是元數(shù)據(jù)的一種形式,提供有關(guān)于程序但不屬于程序本身的數(shù)據(jù)衔憨。注解對它們注解的代碼的操作沒有直接影響叶圃。
  • 意義
    注解本身沒有任何意義,單獨的注解就是一種注釋践图,他需要結(jié)合其他如反射掺冠、插樁等技術(shù)才有意義。
    注解01.png

二 注解聲明

  • 聲明一個注解類型
    Java中所有的注解,默認實現(xiàn)Annotation 接口:
public interface Annotation {
    boolean equals(Object var1);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

與聲明一個"Class"不同的是德崭,注解的聲明使用@interface 關(guān)鍵字斥黑。一個注解的聲明如下:

public @interface Lance {

}

三 元注解

在定義注解時,注解類也能夠使用其他的注解聲明眉厨。對注解類型進行注解的注解類锌奴,我們稱之為 metaannotation(元注解)
一般的,我們在定義自定義注解時憾股,需要指定的元注解有兩個 :

另外還有@Documented 與 @Inherited 元注解鹿蜀,前者用于被javadoc工具提取成文檔,后者表示允許子類
繼承父類中定義的注解服球。

1. @Target
注解標記另一個注解茴恰,以限制可以應(yīng)用注解的 Java 元素類型。目標注解指定以下元素類型之一作為其值:

  • ElementType.ANNOTATION_TYPE 可以應(yīng)用于注解類型斩熊。
  • ElementType.CONSTRUCTOR 可以應(yīng)用于構(gòu)造函數(shù)往枣。
  • ElementType.FIELD 可以應(yīng)用于字段或?qū)傩浴?/li>
  • ElementType.LOCAL_VARIABLE 可以應(yīng)用于局部變量。
  • ElementType.METHOD 可以應(yīng)用于方法級注解座享。
  • ElementType.PACKAGE 可以應(yīng)用于包聲明婉商。
  • ElementType.PARAMETER 可以應(yīng)用于方法的參數(shù)。
  • ElementType.TYPE 可以應(yīng)用于類的任何元素渣叛。

2. @Retenton
注解指定標記注解的存儲方式:

  • RetentionPolicy.SOURCE - 標記的注解僅保留在源級別中,并被編譯器忽略盯捌。
  • RetentionPolicy.CLASS - 標記的注解在編譯時由編譯器保留淳衙,但 Java 虛擬機(JVM)會忽略。
  • RetentionPolicy.RUNTIME - 標記的注解由 JVM 保留饺著,因此運行時環(huán)境可以使用它箫攀。

@Retention 三個值中 SOURCE < CLASS < RUNTIME,即CLASS包含了SOURCE幼衰,RUNTIME包含SOURCE靴跛、
CLASS。下文會介紹他們不同的應(yīng)用場景渡嚣。

下面來看例子:

//@Target(ElementType.TYPE) 只能在類上標記該注解
@Target({ElementType.TYPE,ElementType.FIELD}) // 允許在類與類屬性上標記該注解
@Retention(RetentionPolicy.SOURCE) //注解保留在源碼中
public @interface Lance {
}

四 注解類型元素

在上文元注解中梢睛,允許在使用注解時傳遞參數(shù)。我們也能讓自定義注解的主體包含 annotation type element (注解
類型元素) 聲明识椰,它們看起來很像方法绝葡,可以定義可選的默認值。

public @interface Lance {
    String value(); //無默認值
    int age() default 1; //有默認值
}

注意:在使用注解時腹鹉,如果定義的注解中的類型元素?zé)o默認值藏畅,則必須進行傳值。

@Lance("技術(shù)好") //如果只存在value元素需要傳值的情況功咒,則可以省略:元素名=
@Lance(value="技術(shù)好",age = 2)
int i;

五 注解的保留級別以及應(yīng)用場景

注解保留級別.png
注解的應(yīng)用場景.png

SOURCE

1. IDE語法檢查
在Android開發(fā)中愉阎, support-annotations 與androidx.annotation) 中均有提供@IntDef 注解绞蹦,此注解的定義如
下:

@Retention(SOURCE) //源碼級別注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
int[] value() default {};
boolean flag() default false;
boolean open() default false;
}
  • 首先看看枚舉方法如何語法檢查的
public enum Week {
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
}
 //枚舉方法
    public static void testEnum(Week week){
        String str = "";
        switch (week) {
            case MONDAY:
                str = ">今天星期一";
                break;
            case TUESDAY:
                str = ">今天星期二";
                break;
            case WEDNESDAY:
                str = "今天星期三";
                break;
            case THURSDAY:
                str = ">今天星期四";
                break;
            case FRIDAY:
                str = ">今天星期五";
                break;
            case SATURDAY:
                str = ">今天星期六";
                break;
            case SUNDAY:
                str = ">今天周末";
                break;
        }
        System.out.print(str);
    }

Java中Enum(枚舉)的實質(zhì)是特殊單例的靜態(tài)成員變量,在運行期所有枚舉類作為單例榜旦,全部加載到內(nèi)存中幽七。比常量多5到10倍的內(nèi)存占用。

  • 而現(xiàn)在為了進行內(nèi)存優(yōu)化章办,我們現(xiàn)在不再使用枚舉锉走,則方法定義為:
    public static final int MONDAY = 0;
    public static final int TUESDAY = 1;
    public static final int WEDNESDAY = 2;
    public static final int THURSDAY = 3;
    public static final int FRIDAY = 4;
    public static final int SATURDAY = 5;
    public static final int SUNDAY = 6;
    //改為
    public static void testEnum(int week){
            case MONDAY:
                str = ">今天星期一";
                break;
            case TUESDAY:
                str = ">今天星期二";
                break;
            case WEDNESDAY:
            ........
    }

但是因為是基本類型 無法限制傳遞參數(shù) 可以傳遞0—6 之外任何值,所以這種方法是不行的

  • 采用注解可以替代枚舉 且可以達到代碼檢查 限制參數(shù)傳遞的效果
 public static final int MONDAY = 0;
    public static final int TUESDAY = 1;
    public static final int WEDNESDAY = 2;
    public static final int THURSDAY = 3;
    public static final int FRIDAY = 4;
    public static final int SATURDAY = 5;
    public static final int SUNDAY = 6;

 @IntDef(value = {MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY})//限定
    @Target({ElementType.PARAMETER})//作用于參數(shù)的注解
    @Retention(RetentionPolicy.SOURCE)//保留級別為源碼
    public @interface week{

    }

public static void testAn(@week int week) {
        String str = "";
        switch (week) {
            case 0:
                str = "今天星期一";
                break;
            case 1:
                str = "今天星期二";
                break;
            case 2:
                str = "今天星期三";
                break;
            case 3:
                str = "今天星期四";
                break;
            case 4:
                str = "今天星期五";
                break;
            case 5:
                str = "今天星期六";
                break;
            case 6:
                str = "今天周末";
                break;
        }
        System.out.print(str);
    }

這里有個注意點:Add library 'Gradle: com.android.support:support-annotations:27.1.1@jar' to classpath
在編寫Android程序時藕届,我們經(jīng)常使用 @NonNull挪蹭,@UiThread,@IntegerRes等這些Android提供的注解:但是當(dāng)你想在一個 Java Library中使用 support-annotations時,你卻發(fā)現(xiàn) gradle 一直彈出 :Add library 'Gradle: com.android.support:support-annotations:X.X.X@jar' to classpath 這個時候可以自己下載support-annotations 手動添加休偶、或者使用SDK已下載好的 手動添加到lib路徑下即可

2. APT注解處理器
APT全稱為:"Anotation Processor Tools"梁厉,意為注解處理器。顧名思義踏兜,其用于處理注解

CLASS

定義為CLASS 的注解词顾,會保留在class文件中,但是會被虛擬機忽略(即無法在運行期反射獲取注解)碱妆。此時完全符合
此種注解的應(yīng)用場景為字節(jié)碼操作肉盹。如:AspectJ、熱修復(fù)Roubust中應(yīng)用此場景疹尾。
所謂字節(jié)碼操作即為上忍,直接修改字節(jié)碼Class文件以達到修改代碼執(zhí)行邏輯的目的。在程序中有多處需要進行是否
登錄的判斷纳本。

RUNTIME

注解保留至運行期窍蓝,意味著我們能夠在運行期間結(jié)合反射技術(shù)獲取注解中的所有信息。

代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末繁成,一起剝皮案震驚了整個濱河市吓笙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巾腕,老刑警劉巖面睛,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異祠墅,居然都是意外死亡侮穿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門毁嗦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亲茅,“玉大人,你說我怎么就攤上這事】寺啵” “怎么了茵肃?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袭祟。 經(jīng)常有香客問我验残,道長,這世上最難降的妖魔是什么巾乳? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任您没,我火速辦了婚禮,結(jié)果婚禮上胆绊,老公的妹妹穿的比我還像新娘氨鹏。我一直安慰自己,他們只是感情好压状,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布仆抵。 她就那樣靜靜地躺著,像睡著了一般种冬。 火紅的嫁衣襯著肌膚如雪镣丑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天娱两,我揣著相機與錄音莺匠,去河邊找鬼。 笑死十兢,一個胖子當(dāng)著我的面吹牛慨蛙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纪挎,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跟匆!你這毒婦竟也來了异袄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤玛臂,失蹤者是張志新(化名)和其女友劉穎烤蜕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迹冤,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡讽营,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了泡徙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橱鹏。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莉兰,到底是詐尸還是另有隱情挑围,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布糖荒,位于F島的核電站杉辙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捶朵。R本人自食惡果不足惜蜘矢,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望综看。 院中可真熱鬧品腹,春花似錦、人聲如沸寓搬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽句喷。三九已至镣典,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唾琼,已是汗流浹背兄春。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锡溯,地道東北人赶舆。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像祭饭,于是被迫代替她去往敵國和親芜茵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345