我們IDE編程時(shí)經(jīng)常會(huì)自動(dòng)給我們添加Override佩憾、Deprecated等以及三方框架注解哮伟,這些注解是怎么定義以及工作的,我們?cè)撛趺醋远x注解妄帘,這些可能是一個(gè)入門程序猿所不了解的,這篇文章以及下一篇如何編寫自定義注解將一點(diǎn)點(diǎn)的介紹注解概念以及如何自定義注解池凄,希望能給一些對(duì)注解有困惑的開發(fā)一點(diǎn)幫助
基本概念
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ì)中。
Annotation的成員在Annotation類型中以無(wú)參數(shù)的方法的形式被聲明署海。其方法名和返回值定義了該成員的名字和類型吗购。在此有一個(gè)特定的默認(rèn)語(yǔ)法:允許聲明任何Annotation成員的默認(rèn)值:一個(gè)Annotation可以將name=value對(duì)作為沒有定義默認(rèn)值的Annotation成員的值,當(dāng)然也可以使用name=value對(duì)來(lái)覆蓋其它成員默認(rèn)值砸狞。這一點(diǎn)有些近似類的繼承特性巩搏,父類的構(gòu)造函數(shù)可以作為子類的默認(rèn)構(gòu)造函數(shù),但是也可以被子類覆蓋趾代。
Annotation能被用來(lái)為某個(gè)程序元素(類贯底、方法、成員變量等)關(guān)聯(lián)任何的信息撒强。需要注意的是禽捆,這里存在著一個(gè)基本的規(guī)則:Annotation不能影響程序代碼的執(zhí)行,無(wú)論增加飘哨、刪除 Annotation胚想,代碼都始終如一的執(zhí)行。
首先看下我們最長(zhǎng)用到的JDK內(nèi)置注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Override注解又使用了注解芽隆?沒錯(cuò)浊服,@Target和@Retention是元注解(用于給其注解其他注解,一般自定義注解都要使用)胚吁,到這里我們可以給注解分下類:
根據(jù)注解使用方法和用途牙躺,我們可以將annotation分三類:
1、系統(tǒng)注解:JDK提供了三個(gè)系統(tǒng)注解Override(標(biāo)記此方法是覆蓋了父類的方法)腕扶、Deprecated(用于標(biāo)記方法等過(guò)時(shí)孽拷,一般都會(huì)有新的API提供)、SuppressWarnnings(用于通知java編譯器禁止特定的編譯警告)
2半抱、元注解:Java5.0定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型
①@Target:用于說(shuō)明Annotation所修飾的范圍脓恕,系統(tǒng)代碼如下
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Target {
ElementType[] value();
}
ElementType是個(gè)枚舉類型,取值有:
1.CONSTRUCTOR:用于描述構(gòu)造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部變量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述參數(shù)
7.TYPE:用于描述類窿侈、接口(包括注解類型) 或enum聲明
②@Retention:定義Annotation被保留的時(shí)間長(zhǎng)短即注解生命周期限制
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Retention {
RetentionPolicy value();
}
RetentionPolicy也是個(gè)枚舉類型炼幔,取值有:
1.SOURCE:在源文件中有效(即源文件保留,被編譯器丟棄)
2.CLASS:在class文件中有效(即class保留史简,被編譯但虛擬機(jī)忽略)
3.RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留乃秀,class裝載的時(shí)候讀取)
③@Documented:用于描述其它類型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Documented {
}
④@Inherited:用于標(biāo)記注解是被繼承的环形,如果一個(gè)使用了@Inherited修飾的annotation類型被用于一個(gè)class策泣,則這個(gè)annotation將被用于該class的子類
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Inherited {
}
3、自定義注解:自定義注解一般包含編譯注解和運(yùn)行時(shí)注解抬吟,根據(jù)系統(tǒng)提供API以及相關(guān)機(jī)制在編譯或者運(yùn)行時(shí)獲取想要的數(shù)據(jù)萨咕,自定義注解形式和系統(tǒng)注解以及元注解一樣,下文會(huì)有自定義注解的Demo火本。
從上面的元注解來(lái)看危队,注解又分為:
1、標(biāo)記注解钙畔,比如@Override茫陆、@Inherited、@Documented擎析。這類注解是沒有元素的簿盅,用于標(biāo)記元素特性比如過(guò)時(shí)、覆蓋父類方法等
2揍魂、單值注解桨醋,只有一個(gè)元素的注解,比如@Target现斋、@Retention等
3喜最、完整注解 ,除了①和②的所有注解
自定義注解
為了下面我們自定義注解Demo庄蹋,我們先了解一下自定義注解的寫法瞬内。使用@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、Annotation以及這些類型的數(shù)組)忆谓●勺埃可以通過(guò)default來(lái)聲明參數(shù)的默認(rèn)值。
注解元素定義形式如:
public @interface 注解名 {定義體}//public 可以省略
public String name() default "fieldName";//元素定義樣式</pre>
使用形式:
@注解名(name1= value1,name2 = value2)
單值注解定義和使用還有簡(jiǎn)寫方式:
元素定義:
String value() default “value”
使用形式:
@注解名(value)
定義注解和使用注解都很容易,關(guān)鍵還是要處理注解哨免,如果沒有處理注解的方法那么注解就僅僅相當(dāng)于注釋了茎活。所以創(chuàng)建注解處理器是很重要的,獲取注解之前我們肯定要先獲取注解作用的Target比如:
Class:類定義
Constructor:構(gòu)造器定義
Field:類的成員變量
Method:類中的方法
Package:類的包定義(有點(diǎn)不懂@**@)
這幾個(gè)都是AnnotatedElement接口實(shí)現(xiàn)類琢唾,運(yùn)行時(shí)注解可以通過(guò)java.lang.reflect包下的反射API運(yùn)行時(shí)獲取载荔,含的獲取注解的方法如下:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定類型的注解采桃,如果該類型注解不存在懒熙,則返回null。
方法2:Annotation[] getAnnotations():返回該程序元素上存在的所有注解普办。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的注解工扎,存在則返回true,否則返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注釋衔蹲。與此接口中的其他方法不同肢娘,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上舆驶,則返回長(zhǎng)度為零的一個(gè)數(shù)組橱健。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響贞远。
由于篇幅的原因自定義注解(編譯時(shí)注解以及運(yùn)行時(shí)注解Demo)將在下一篇博客如何編寫自定義注解中介紹
最后用一張思維導(dǎo)圖來(lái)總結(jié)一下注解參考文獻(xiàn):深入理解java注解