Android注解,這幾篇文章就夠了(二)注解

一 前言

Java注解(Annotation)又稱Java標注,是JDK5.0引入的一種注釋機制。網上也有很多關于Java Annotation的文章,看得使人眼花繚亂,很難理解。
那么到底什么是注解,注解有什么作用,我舉個栗子先,



《奇葩說》第六季已經開播了,這里面我最喜歡的辯手是陳銘,為人師表,談吐舉止得體,他那獨樹一幟的辯論風格,令人聽了不禁十分感動,因為他那是“站在宇宙中心呼喚愛”,以至于他每次出來,“站在宇宙中心呼喚愛”就立刻出現在我的腦海里,然后繼續聽他的辯論,果然如此。“站在宇宙中心呼喚愛”就如同一個標簽,貼在了陳銘身上。

以同樣的方式理解Annotation,Annotation就如同一個標簽一樣,只不過它是貼在了代碼上。單純的Annotation對程序的運行并無影響,就像“站在宇宙中心呼喚愛”這個標簽對于陳銘老師來說,并沒有什么影響,但是“站在宇宙中心呼喚愛”可以用來解釋陳銘老師,同樣Annotation也是對用Annotation注解的程序的解釋,不過是要借助工具,就是上一篇文章介紹的APT。

說了那么多,就是為了理解Annotation,Annotation其實也和class,interface一樣,屬于java的一種類型,只不過在開發中比較少見,為了理解,我們可以假想用標簽來理解。

二 注解的語法

(一) 注解的定義

注解使用@interface關鍵字進行定義,看形式和interface差不多,但是加了一個@符號。

public @interface MyAnnotation {
    
}

上面的代碼創建了一個MyAnnotation的注解,你可以理解為創建了一個MyAnnotation的標簽,拿著這個標簽,可以給其它的代碼貼上次標簽。

(二)注解的使用

上面創建了一個注解,但是注解怎么使用呢?

@MyAnnotation
public class MyTest {
    
}

上面的代碼創建了一個注解,然后我們定義了一個類,叫MyTest,在類定義的地方加上@MyAnnotation,就用我們定義的注解,注解到了MyTest類中,你可以簡單理解成,在MyTest類上貼了一張MyAnnotation的標簽。

(三) 元注解

元注解又是什么呢?
要理解上面定義的注解,就必須要理解元注解,元注解是一種基本的注解,它是可以注解到注解上的注解。元注解主要是起對注解解釋說明作用。

元注解有五種,@Retention、@Documented、@Target、@Inherited、@Repeatable 。

① @Retention

Retention意為保留的意思,注解加上@Retention表示注解的存活時間。
它的取值如下:

取值 意義
RetentionPolicy.SOURCE 注解只在于源碼階段保留,在編譯器進行編譯時它將會被丟棄
RetentionPolicy.CLASS 注解將會保留到編譯階段,但是并不會加載到JVM中
RetentionPolicy.RUNTIME 注解可以保留到程序運行的時候,它會被加載到JVM中

下面對我的注解加上元注解,使我們定義的注解保留到程序運行時。

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

}
② @Documented

這個元注解很簡單,表示該注解是否可以生成JavaDoc,加上該注解則可以將該注解生成JavaDoc。

③ @Target

Target意為目標的意思,@Target指定了注解運用的地方,即注解的作用域。
@Target的作用域如下所示:

取值 作用域
ElementType.TYPE 給一個類型進行注解,比如類、接口、枚舉
ElementType.FIELD 可以給一個屬性進行注解
ElementType.METHOD 可以給方法進行注解
ElementType.PARAMETER 可以對一個方法內的參數添加注解
ElementType.CONSTRUCTO 可以對構造函數添加注解
ElementType.LOCAL_VARIABLE 可以對局部變量添加注解
ElementType.ANNOTATION_TYPE 可以對一個注解進行注解
ElementType.PACKAGE 可以對一個包進行注解

@Target也可以接受一個數組作為參數,設置多個多個注解的作用域。
下面對我們定義的注解加上@Target元注解,使我們定義的注解可以注解到屬性和方法上。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation {

}
④ @Inherited

Inherited意為繼承的意思,默認是false,它并不是說注解本身可以繼承,而是說如果一個類,被一個有@Inherited的注解注解過,如果它的子類沒有被任何注解注解,那么它的子類就繼承了它的注解。說起來比較模糊,show me the code!

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE}
@Inherited
public @interface MyAnnotation {

}

@MyAnnotation
public class MyTest {

}

public class MyTestChild extends MyTest{

}

注解MyAnnotation被@Inherited元注解注解了,
類 MyTest,使用MyAnnotation進行注解,
MyTestChild繼承MyTest,并沒有任何注解,MyTestChild也擁有了MyAnnotation注解。

(四) 注解的屬性

注解的屬性,也叫注解的成員變量,注解中只有成員變量,沒有方法。
注解的成員變量在注解的定義中,以 無形參的方法 形式聲明,方法名就是該成員變量的名字,返回值定義了該成員變量的類型。

下面的注解定義了兩個成員變量,分別是int類型的id,和String類型的name。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Inherited
public @interface MyAnnotation {
    int id();
    String name();
}

在使用我們自定義的注解時,我們應該對屬性進行賦值,賦值的時候,在括號內以value=“”的形式賦值,多個屬性用 , 間隔開。

@MyAnnotation(id=1,name="jack")
public class MyTest {

}

定義注解屬性的時候,可以有默認值,默認值用default關鍵字指定。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Inherited
public @interface MyAnnotation {
    int id();
    String name() default "frank";
}

(五) Java內置的注解

上面我們自定義了注解,java本身已經提供了一些注解,

  • 1 @Override ,這個注解最熟悉了,提示子類中要復寫父類中被@Override修飾的方法。
  • 2 @Deprecated,用來標記過時的元素,比如過時的方法,過時的類,過時的成員變量等。
  • 3 @SuppressWarnings,阻止警告。
  • 4 @SafeVarargs,參數安全類型注解。
  • 5 @FunctionalInterface,函數式接口注解,函數式接口就是只有一個方法的接口。

三 注解的提取

上面講了注解的定義和使用,我們在MyTest類加上了我們定義的注解MyAnnotation,

@MyAnnotation(id=1,name="jack")
public class MyTest {

}

那么加上這個注解以后,怎么提取注解的內容呢?
要正確提取注解,需要反射。

注解和反射

注解通過反射獲取。

  • 1 通過Class對象的isAnnotationPresent()方法判斷它是否應用了某個注解。
public boolean isAnnotationPresent(@RecentlyNonNull Class<? extends Annotation> annotationClass) {
        throw new RuntimeException("Stub!");
    }

  • 2 通過getAnnotation()方法來獲取Annotation對象。
@Nullable
    public <A extends Annotation> A getAnnotation(@NonNull Class<A> annotationClass) {
        throw new RuntimeException("Stub!");
    }

現在我們來獲取MyTest上的注解。

@MyAnnotation(id=1,name="jack")
public class MyTest {
    public static void main(String[] args){
        boolean hasAnnotation=MyTest.class.isAnnotationPresent(MyAnnotation.class);
        if (hasAnnotation){
            MyAnnotation myAnnotation=MyTest.class.getAnnotation(MyAnnotation.class);
            System.out.println("id=="+myAnnotation.id());
            System.out.println("name=="+myAnnotation.name());
        }
    }
}

運行結果:


四 注解的使用場景

注解在一下三種時機發揮作用:

  • 1 程序開發時,在開發程序時,經常用到@Override @Nullable等注解,這些注解和IDE共同作用是提示代碼編寫過程中的錯誤,這些注解在編譯階段被編譯器丟棄,在class文件中不會出現.
  • 2 程序編譯時,軟件工具可以用來利用注解信息來生成代碼、Html文檔或者做其它相應處理。
  • 3 程序運行時,當程序運行的時候,我們希望通過獲取標注的注解執行不同的邏輯,如EventBus使用不同線程發送消息。

注解并不是代碼的一部分,當開發者使用了Annotation注解以后,這些Annotation不會自己生效,當使用了注解時,一般通過以下兩種方法處理

  • 通過反射自己提取注解
  • 由開發者提供相應的代碼來提取并處理這些Annotation信息

這些處理Annotation信息的代碼,我們統稱為APT(Annotation Processing Tool)。想了解APT的可以看下這篇文章

下一篇文章自己寫個注解處理器
通過寫一個簡單的注解處理器來再次理解注解。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一種元程序中的元素關聯任何信息和...
    九尾喵的薛定諤閱讀 3,204評論 0 2
  • 關于注解首先引入官方文檔的一句話:Java 注解用于為 Java 代碼提供元數據。作為元數據,注解不直接影響你的代...
    編程小世界閱讀 491評論 0 0
  • java自定義注解 Java注解是附加在代碼中的一些元信息,用于一些工具在編譯、運行時進行解析和使用,起到說明、配...
    尼爾君閱讀 522評論 0 0
  • 什么是注解 Java Annotation是JDK5.0引入的一種注釋機制,可以為程序的元素(包、類、接口、字段、...
    LouisXWB閱讀 190評論 0 1
  • *各位爸爸媽媽,你知道有一種現象叫做“習慣性愚蠢”嗎?或許,孩子正在萌發這種現象,而罪魁禍首就是你…… “習慣性愚...
    心理咨詢師Lily閱讀 838評論 0 1