一小時(shí)搞明白自定義注解(Annotation)

一小時(shí)搞明白自定義注解(Annotation)

原創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

什么是注解

Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和著任何元數(shù)據(jù)(metadata)的途徑和方法。Annotion(注解)是一個(gè)接口为牍,程序可以通過(guò)反射來(lái)獲取指定程序元素的 Annotion對(duì)象野宜,然后通過(guò) Annotion對(duì)象 來(lái)獲取注解里面的元數(shù)據(jù)闷袒。

Annotation(注解)是JDK5.0及以后版本引入的犀斋。它可以用于創(chuàng)建文檔奏篙,跟蹤代碼中的依賴性润努,甚至執(zhí)行基本編譯時(shí)檢查关斜。從某些方面看,annotation 就像修飾符一樣被使用铺浇,并應(yīng)用于包痢畜、類 型、構(gòu)造方法鳍侣、方法丁稀、成員變量、參數(shù)倚聚、本地變量的聲明中线衫。這些信息被存儲(chǔ)在 Annotation 的“name=value”結(jié)構(gòu)對(duì)中。

什么是metadata元數(shù)據(jù)

元數(shù)據(jù)從metadata一詞譯來(lái)惑折,就是“關(guān)于數(shù)據(jù)的數(shù)據(jù)”的意思授账。

元數(shù)據(jù)的功能作用有很多枯跑,比如:你可能用過(guò) Javadoc 的注釋自動(dòng)生成文檔。這就是元數(shù)據(jù)功能的一種白热×仓總的來(lái)說(shuō),元數(shù)據(jù)可以用來(lái)創(chuàng)建文檔屋确,跟蹤代碼的依賴性纳击,執(zhí)行編譯時(shí)格式檢查,代替已有的配置文件乍恐。如果要對(duì)于元數(shù)據(jù)的作用進(jìn)行分類评疗,目前還沒(méi)有明確的定義,不過(guò)我們可以根據(jù)它所起的作用茵烈,大致可分為三類:

1. 編寫(xiě)文檔:通過(guò)代碼里標(biāo)識(shí)的元數(shù)據(jù)生成文檔

2. 代碼分析:通過(guò)代碼里標(biāo)識(shí)的元數(shù)據(jù)對(duì)代碼進(jìn)行分析

3. 編譯檢查:通過(guò)代碼里標(biāo)識(shí)的元數(shù)據(jù)讓編譯器能實(shí)現(xiàn)基本的編譯檢查

Annotation和Annotation類型

Annotation使用了在 java5.0 所帶來(lái)的新語(yǔ)法百匆,它的行為十分類似publicfinal這樣的修飾符呜投。每個(gè) Annotation 具有 一個(gè)名字 和 成員個(gè)數(shù)>=0加匈。每個(gè) Annotation 的成員具有被稱為 name=value 對(duì)的名字和值(就像 javabean 一樣),name=value 裝載了 Annotation 的信息仑荐。

Annotation類型定義了 Annotation 的名字雕拼、類型、成員默認(rèn)值粘招。一個(gè) Annotation類型 可以說(shuō)是一個(gè)特殊的java接口啥寇,它的成員變量是受限制的,而聲明 Annotation類型 時(shí)需要使用新語(yǔ)法洒扎。當(dāng)我們通過(guò) java反射api 訪問(wèn) Annotation 時(shí)辑甜,返回值將是一個(gè)實(shí)現(xiàn)了該 ?annotation類型 接口的對(duì)象,通過(guò)訪問(wèn)這個(gè)對(duì)象我們能方便的訪問(wèn)到其 Annotation 成員袍冷。后面的章節(jié)將提到在 java5.0 的 java.lang 包里包含的3個(gè)標(biāo)準(zhǔn) Annotation類型磷醋。

注解的分類

根據(jù)注解的參數(shù)個(gè)數(shù)分類:

1.標(biāo)記注解,一個(gè)沒(méi)有成員的Annotation類型被稱為標(biāo)記注解胡诗,這種類型僅僅使用自身的存在與否來(lái)為我們提供信息邓线,比如常見(jiàn)的@Override

2.單值注解

3.完整注解

根據(jù)注解使用的方法和用途分類:

1.JDK內(nèi)置系統(tǒng)注解

2.元注解

3.自定義注解

元注解

元注解的作用就是負(fù)責(zé)注解其他注解,Java?5.0定義了4個(gè)meta-annotation類型煌恢,用來(lái)提供對(duì)愛(ài)他的 annotation 類型做說(shuō)明骇陈。

java.lang.annotation

@Target

@Retention

@Document

@Inhrited

@Target

修飾的對(duì)象范圍:packages、types(類瑰抵、接口缩歪、枚舉、Annotation類型)谍憔、類型成員(方法匪蝙、構(gòu)造方法、成員變量习贫、枚舉值)逛球、方法參數(shù)和本地變量(如循環(huán)變量、catch參數(shù))苫昌。

作用:用于描述注解的使用范圍颤绕。

ElementType取值:

1. CONSTRUCTOR:用于描述構(gòu)造器

2. FIELD:用于描述域

3. LOCAL_VARIABLE:用于描述局部變量

4. METHOD:用于描述方法

5. PACKAGE:用于描述包

6. PARAMETER:用于描述參數(shù)

7. TYPE:用于描述類、接口(包括注解類型) 或enum聲明

例如祟身,Name 可以注解類的成員變量:

@Target(ElementType.FIELD)@Documented

public@interfaceName{Stringvalue() default "";}

Person 可以注解類奥务、接口(包括注解類型)、或者enum聲明:

@Target(ElementType.TYPE)

public@interfacePerson{

Stringvalue() default "";}

@Retention

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

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

RetentionPoicy取值:

SOURCE:在源文件中有效(即源文件保留)

CLASS:在class文件中有效(即class保留)

RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)

例如:Name 注解的 RetentionPolicy 的值為RUNTIME担神,這樣注解處理器可以通過(guò)反射楼吃,獲取到該注解的屬性,從而做一些運(yùn)行時(shí)的邏輯處理妄讯。

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public@interfaceName{

Stringvalue() default "";}

@Document

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

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

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public@interfaceName{

Stringvalue() default "";}

@Inhrited

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

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

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

自定義注解

使用@interface自定義注解時(shí)组民,自動(dòng)繼承了 java.lang.annotation.Annotation 接口棒仍,由編譯程序自動(dòng)完成其他細(xì)節(jié)。在定義注解時(shí)臭胜,不能繼承其他的注解或接口莫其。@interface 用來(lái)聲明一個(gè)注解,其中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù)耸三。方法的名稱就是參數(shù)的名稱乱陡,返回值類型就是參數(shù)的類型(返回值類型只能是 基本類型、Class仪壮、String憨颠、enum)【Σ担可以通過(guò)default來(lái)聲明參數(shù)的默認(rèn)值烙心。

自定義注解格式:

public @interface 注解名{注解體}

所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short)

String類型

Class類型

enum類型

Annotation類型

以上所有類型的數(shù)組

Annotation類型里面的參數(shù)該怎么設(shè)定:

第一,只能用 public 或 默認(rèn)(default) 這兩個(gè)訪問(wèn)權(quán)修飾.例如,String value();這里把方法設(shè)為 defaul 默認(rèn)類型;

第二,參數(shù)成員只能用基本類型 byte,short,char,int,long,float,double,boolean 八種基本數(shù)據(jù)類型 和 String,Enum,Class,annotations 等數(shù)據(jù)類型,以及這一些類型的數(shù)組.例如,String value();這里的參數(shù)成員就為String;

第三,如果只有一個(gè)參數(shù)成員,最好把參數(shù)名稱設(shè)為"value",后加小括號(hào).例:下面的例子 Name 注解就只有一個(gè)參數(shù)成員乏沸。

Name姓名注解:

Gander性別注解:

Profile個(gè)人資料注解:

注解元素的默認(rèn)值

注解元素必須有確定的值淫茵,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定蹬跃,非基本類型的注解元素的值不可為null匙瘪。因此, 使用空字符串或0作為默認(rèn)值是一種常用的做法。這個(gè)約束使得處理器很難表現(xiàn)一個(gè)元素的存在或缺失的狀態(tài)蝶缀,因?yàn)槊總€(gè)注解的聲明中丹喻,所有元素都存在,并且都具有相應(yīng)的值翁都,為了繞開(kāi)這個(gè)約束碍论,我們只能定義一些特殊的值,例如空字符串或者負(fù)數(shù)柄慰,一次表示某個(gè)元素不存在鳍悠,在定義注解時(shí),這已經(jīng)成為一個(gè)習(xí)慣用法坐搔。

注解處理器類庫(kù)(java.lang.reflect.AnnotatedElement)

注解元素Java使用 Annotation 接口來(lái)代表程序元素前面的注解藏研,該接口是所有 Annotation類型 的父接口。除此之外概行,Java 在 java.lang.reflect 包下新增了 AnnotatedElement 接口蠢挡,該接口代表程序中可以接受注解的程序元素,該接口主要有如下幾個(gè)實(shí)現(xiàn)類:

Class:類定義

Constructor:構(gòu)造器定義

Field:累的成員變量定義

Method:類的方法定義

Package:類的包定義

當(dāng)一個(gè) Annotation 被定義為運(yùn)行時(shí)Annotation后,改注解才是運(yùn)行時(shí)可見(jiàn)的业踏,當(dāng)class文件被裝載時(shí)被保存在class文件中的Annotation才會(huì)被虛擬機(jī)讀取禽炬。

AnnotatedElement接口提供了以下四個(gè)方法來(lái)訪問(wèn) Annotation 的信息:

方法1: T getAnnotation(Class annotationClass):返回改程序元素上存在的、指定類型的注解勤家,如果該類型注解不存在瞎抛,則返回null。

方法2:Annotation[] getAnnotations():返回該程序元素上存在的所有注解却紧。

方法3:boolean is AnnotationPresent(Class annotationClass):判斷該程序元素上是否包含指定類型的注解,存在則返回true胎撤,否則返回false.

方法4:Annotation[] getDeclaredAnnotations()返回直接存在于此元素上的所有注釋晓殊。與此接口中的其他方法不同,該方法將忽略繼承的注釋伤提。(如果沒(méi)有注釋直接存在于此元素上巫俺,則返回長(zhǎng)度為零的一個(gè)數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組肿男;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響介汹。

我們?yōu)榍懊娑x好的自定義注解寫(xiě)一個(gè)簡(jiǎn)單的處理器:

使用自定義注解:

運(yùn)行:

CustomUtils.getInfo(Person.class);

輸出:

完。舶沛。嘹承。。如庭。叹卷。。坪它。骤竹。。往毡。蒙揣。。开瞭。懒震。。惩阶。挎狸。。断楷。锨匆。

文章原創(chuàng)作者GuoLin 書(shū)籍推薦

郭林大神原創(chuàng)android 書(shū)籍:《第一行代碼 android》

淘寶鏈接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恐锣,更是在濱河造成了極大的恐慌茅主,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件土榴,死亡現(xiàn)場(chǎng)離奇詭異诀姚,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玷禽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)赫段,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人矢赁,你說(shuō)我怎么就攤上這事糯笙。” “怎么了撩银?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵给涕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我额获,道長(zhǎng)够庙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任抄邀,我火速辦了婚禮耘眨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撤摸。我一直安慰自己毅桃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布准夷。 她就那樣靜靜地躺著钥飞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衫嵌。 梳的紋絲不亂的頭發(fā)上读宙,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音楔绞,去河邊找鬼结闸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酒朵,可吹牛的內(nèi)容都是我干的桦锄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蔫耽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼结耀!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤图甜,失蹤者是張志新(化名)和其女友劉穎碍粥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體黑毅,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚼摩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了矿瘦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枕面。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缚去,靈堂內(nèi)的尸體忽然破棺而出膊畴,到底是詐尸還是另有隱情,我是刑警寧澤病游,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站稠通,受9級(jí)特大地震影響衬衬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜改橘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一滋尉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧飞主,春花似錦狮惜、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至筏餐,卻和暖如春开泽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魁瞪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工穆律, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人导俘。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓峦耘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親旅薄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辅髓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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