整天都說(shuō)注解注解注解,你們了解注解嗎來(lái)自——面試官的靈魂拷問(wèn)

注解

它可以用于創(chuàng)建文檔玛臂,跟蹤代碼中的依賴性迹冤,甚至執(zhí)行基本編譯時(shí)檢查泡徙。注解是以‘@注解名’在代碼中存在的,根據(jù)注解參數(shù)的個(gè)數(shù),我們可以將注解分為:標(biāo)記注解糖荒、單值注解捶朵、完整注解三類综看。它們都不會(huì)直接影響到程序的語(yǔ)義寓搬,只是作為注解(標(biāo)識(shí))存在,我們可以通過(guò)反射機(jī)制編程實(shí)現(xiàn)對(duì)這些元數(shù)據(jù)(用來(lái)描述數(shù)據(jù)的數(shù)據(jù))的訪問(wèn)镣典。另外,你可以在編譯時(shí)選擇代碼里的注解是否只存在于源代碼級(jí)锡溯,或者它也能在class文件祭饭、或者運(yùn)行時(shí)中出現(xiàn)(SOURCE/CLASS/RUNTIME)倡蝙。

元注解作用

如果要對(duì)于元數(shù)據(jù)的作用進(jìn)行分類,還沒(méi)有明確的定義猪钮,不過(guò)我們可以根據(jù)它所起的作用,大致可分為三類:

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

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

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

1檐蚜、注解的作用分類

(1)生成文檔相關(guān)的注釋說(shuō)明:通過(guò)代碼里標(biāo)識(shí)的注解可以生成文檔相關(guān)的注釋說(shuō)明闯第。

下面我們就來(lái)演示一下咳短,首先我們編寫一個(gè)類咙好,添加相關(guān)的注解勾效。

/**

*@authorMr.wu

*@version1.0

*@since1.8

*/

publicclassAnnotationDemo{

/**

? ? *

*@parama

*@paramb

*@returna+b

? ? */

publicintsum(inta,intb){

returna+b;

}

}

然后使用javadoc指令把我們創(chuàng)建的類生成javadoc文檔层宫。

生成之后其监,如下圖所示:

打開(kāi)文檔,如下圖所示:

我們平時(shí)使用的JDK的文檔就是這樣生成的贮庞。

(2)分析運(yùn)行代碼:通過(guò)代碼里標(biāo)識(shí)的注解對(duì)代碼進(jìn)行分析運(yùn)行[使用反射]究西。 最后會(huì)進(jìn)行演示捉邢。

(3)編譯檢查:通過(guò)代碼里的注解讓編譯器實(shí)現(xiàn)編譯檢查伏伐。 例如:我們平時(shí)經(jīng)常使用的override注解晕拆,當(dāng)我們使用此注解時(shí),編譯器就會(huì)檢查該方法是否重寫了父類(或接口)中的方法吝镣。

2末贾、JDK內(nèi)置注解

JDK中內(nèi)置了三個(gè)基本的注解拱撵,下面就來(lái)介紹一下:

@Override: 限定重寫父類中方法, 該注解只能用于方法拴测;

@Deprecated: 用于表示所修飾的元素(類, 方法等)已過(guò)時(shí)集索,通常是因?yàn)樗揎椀慕Y(jié)構(gòu)危險(xiǎn)或存在更好的選擇务荆;

@SuppressWarnings: 抑制編譯器警告毅厚。

3、JDK中的元注解

元注解就是修飾注解的注解酷窥。JDK中有四個(gè)元注解

@Target:表示注解能夠作用的位置。

(1) ElementType.TYPE :可以作用在類妆棒、接口和枚舉類上; (2) ElementType.METHOD :可以作用在方法上毅糟; (3) ElementType.FIELD :可以作用在成員變量上姆另; (4) ElementType.CONSTRUCTOR :可以作用在構(gòu)造器上; (5) ElementType.LOCAL_VARIABLE :可以作用在局部變量上甚侣。

@Retention:表示注解的生命周期殷费,即注解被保留的階段宗兼。

(1) RetentionPolicy.SOURCE :在源文件中有效(即源文件保留)氮采,編譯時(shí)編譯器會(huì)直接丟棄這種策略的注解鹊漠; (2) RetentionPolicy.CLASS : 在class文件中有效(即class保留),當(dāng)運(yùn)行Java程序時(shí), JVM不會(huì)保留注解畔师。這是默認(rèn)值 (3) RetentionPolicy.RUNTIME : 在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留),當(dāng)運(yùn)行 Java 程序時(shí), JVM會(huì)保留注解。程序可以通過(guò)反射獲取該注釋伯铣。

@Documented:表示該注解修飾的注解腔寡,可以被抽取到API文檔中忿磅。 注意:定義為Documented的注解必須設(shè)置Retention值為RetentionPolicy.RUNTIME 葱她。

@Inherited:表示該注解可以被人類繼承。

4览效、自定義注解

自定義注解很簡(jiǎn)單锤灿,格式為:

元注解

public@interface注解

自定義注解時(shí)但校,還有一些要求:

Annotation 的成員變量在 Annotation 定義中以無(wú)參數(shù)方法的形式來(lái)聲明术裸。其方法名和返回值定義了該成員的名字和類型袭艺。我們稱為配置參數(shù)。類型只能是八種基本數(shù)據(jù)類型升敲、String類型、Class類型驴党、enum類型、Annotation類型倔既、以及以上所有類型的數(shù)組攘轩;

可以在定義 Annotation 的成員變量時(shí)為其指定初始值, 指定成員變量的初始值時(shí)使用 default 關(guān)鍵字叉存。指定初始化值的注解歼捏,在使用時(shí)可以不對(duì)成員變量進(jìn)行賦值笨篷。

如果只有一個(gè)成員變量,建議使用參數(shù)名為value率翅;

如果定義的注解含有成員變量,那么使用時(shí)必須進(jìn)行賦值腺晾,除非它有默認(rèn)值,賦值的格式為“成員變量名 = 值”;如果只有一個(gè)成員變量悯蝉,且名稱為value,則可以省略“value=”直接賦值鼻由;

沒(méi)有定義成員變量的 Annotation 稱為標(biāo)記; 包含成員變量的 Annotation 稱為元數(shù)據(jù)。

下面我們就來(lái)自定義一個(gè)簡(jiǎn)單的注解

@Target({ElementType.TYPE,ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public@interfaceMyAnnotation {

Stringvalue();

}

那么注解的實(shí)質(zhì)是什么呢蔼紧?

我們把我們自定義的注解反編譯一下狠轻,如下圖所示:

publicinterfacezzuli.edu.annotation.MyAnnotationextendsjava.lang.annotation.Annotation{

publicabstractjava.lang.Stringvalue();

}

由反編譯后的代碼可知,注解的本質(zhì)實(shí)際上是一個(gè)接口哩至,并且該接口默認(rèn)繼承了 Annotation 接口蜜自。

5卢佣、JDK8中注解的新特性

Java 8對(duì)注解處理提供了兩點(diǎn)改進(jìn):可重復(fù)的注解及可用于類型的注解戈鲁。

@Repeatable:可重復(fù)注解

當(dāng)我們需要重復(fù)使用某個(gè)注解時(shí)婆殿,并且希望利用相同的注解來(lái)表現(xiàn)不同的形式時(shí)婆芦,我們可以借助@Repeatable注解消约。比如:我們?cè)谏钪幸粋€(gè)人往往是具有多種身份或粮,例如我是一家公司的員工渣锦,同時(shí)我還是我父母的孩子等等泡挺,此時(shí)我們就可以使用@Repeatable注解來(lái)完成娄猫。

在Java 8之前沒(méi)有@Repeatable時(shí)媳溺,我們都是通過(guò)定義注解的數(shù)組來(lái)實(shí)現(xiàn)可重復(fù)注解的悬蔽,如下所示:

//定義一個(gè)表示角色的注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Role {

String value();

}

//定義一個(gè)角色數(shù)組的注解,表示可重復(fù)的注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Roles {

Role[] value();

}

//使用表示可重復(fù)注解的Roles注解來(lái)表示人所扮演的不同的角色

@Roles({@Role("employee") ,@Role("son")})

publicclassPeople{

}

在Java 8中出現(xiàn)了@Repeatable可重復(fù)注解之后,變得簡(jiǎn)單了很多虽缕。下面我們就來(lái)演示一下伍派,還是使用上面的例子诉植,方便我們進(jìn)行對(duì)比晾腔。

//定義一個(gè)Role注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Repeatable(Roles.class) //表示Role注解是一個(gè)可重復(fù)注解

public @interface Role {

String value();

}

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Roles {

Role[] value();

}

@Role("employee")

@Role("son")

public class People {

}

類型注解

JDK1.8之后,關(guān)于元注解@Target的參數(shù)類型ElementType枚舉值多了兩個(gè):TYPE_PARAMETER缤至、TYPE_USE嫉到。 (1) ElementType.TYPE_PARAMETER:表示該注解能寫在類型變量的聲明語(yǔ)句中何恶,如:參數(shù)聲明细层、泛型聲明等疫赎; (2) ElementType.TYPE_USE:表示該注解能寫在使用類型的任何語(yǔ)句中捧搞。

6、注解的底層實(shí)現(xiàn)原理

我們?cè)谑褂每蚣軙r(shí)經(jīng)常會(huì)使用注解受葛,那注解底層到底是怎樣執(zhí)行的呢闰渔?下面我們通過(guò)一個(gè)例子來(lái)演示一下:

例子:自定義一個(gè)注解,注解標(biāo)注在哪里就讓哪個(gè)方法執(zhí)行。

//自定義一個(gè)注解

@Retention(RetentionPolicy.RUNTIME)

public @interface MyJunit {

}

public class PrintNumber {

public void showOdd(){//打印奇數(shù)

for(inti =0; i <10; i++) {

if(i %2!=0) {

System.out.print(i+" ");

}

}

}

@MyJunit

public void showEven(){//打印偶數(shù)

for(inti =0; i <10; i++) {

if(i %2==0) {

System.out.print(i+" ");

}

}

}

}

public class JunitTest {

public static void main(String[] args) throws Exception {

//1.創(chuàng)建PrintNumber對(duì)象

PrintNumber printNumber = new PrintNumber();

//2.獲取該類的字節(jié)碼文件對(duì)象

Class clazz = printNumber.getClass();

//3.獲取對(duì)象中的所有方法

Method[] methods = clazz.getMethods();

for(Method method:methods) {

//4.判斷方法上是否有@MyJunit注解

boolean flag = method.isAnnotationPresent(MyJunit.class);

//5.如果方法上有@MyJunit注解狂塘,則執(zhí)行

if(flag){

method.invoke(printNumber);

}

}

}

}

運(yùn)行結(jié)果

由上述代碼可知廊营,注解底層是通過(guò)反射實(shí)現(xiàn)的。

易錯(cuò)點(diǎn):由于注解默認(rèn)的生命周期是在class文件中有效假哎,當(dāng)運(yùn)行Java程序時(shí), 注解就會(huì)失效惧蛹。 所以我們?cè)谧远x注解時(shí),要想在運(yùn)行時(shí)使用沧烈,則應(yīng)該把注解的生命周期設(shè)置為運(yùn)行時(shí)有效(RetentionPolicy.RUNTIME),否則會(huì)報(bào)錯(cuò)惩歉。

總結(jié)

java提供的Documented元注解跟Javadoc的作用是差不多的锨并,其實(shí)它存在的好處是開(kāi)發(fā)人員可以定制Javadoc不支持的文檔屬性包警,并在開(kāi)發(fā)中應(yīng)用壹瘟。如果對(duì)技術(shù)文章殴俱,以及干貨內(nèi)容,程序員生活類文章,感興趣的朋友們可以關(guān)注收藏轉(zhuǎn)發(fā)一下踱讨,期待下一次的文章嗎,那就抓緊關(guān)注我吧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子揭斧,更是在濱河造成了極大的恐慌讹开,老刑警劉巖萧吠,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡琼腔,警方通過(guò)查閱死者的電腦和手機(jī)甥材,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門绪商,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)理张,“玉大人,你說(shuō)我怎么就攤上這事〉聪荩” “怎么了耘沼?”我有些...
    開(kāi)封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赃绊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)校仑,這世上最難降的妖魔是什么稻扬? 我笑而不...
    開(kāi)封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮尘吗,結(jié)果婚禮上黔宛,老公的妹妹穿的比我還像新娘臀晃。我一直安慰自己积仗,他們只是感情好寂曹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著渺氧,像睡著了一般白华。 火紅的嫁衣襯著肌膚如雪贩耐。 梳的紋絲不亂的頭發(fā)上管搪,一...
    開(kāi)封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天奇钞,我揣著相機(jī)與錄音,去河邊找鬼。 笑死纠亚,一個(gè)胖子當(dāng)著我的面吹牛图呢,可吹牛的內(nèi)容都是我干的骗随。 我是一名探鬼主播指蚜,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚕冬!你這毒婦竟也來(lái)了囤热?” 一聲冷哼從身側(cè)響起锨苏,我...
    開(kāi)封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肯夏,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后徊都,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體暇矫,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡房轿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年纷妆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肿轨,靈堂內(nèi)的尸體忽然破棺而出椒袍,到底是詐尸還是另有隱情辨赐,我是刑警寧澤帆焕,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布折晦,位于F島的核電站,受9級(jí)特大地震影響式散,放射性物質(zhì)發(fā)生泄漏暴拄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一豁鲤、第九天 我趴在偏房一處隱蔽的房頂上張望鲸沮。 院中可真熱鬧,春花似錦讼溺、人聲如沸藻懒。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蝶锋。三九已至,卻和暖如春慌闭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背布讹。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工呼股, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耕魄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓彭谁,卻偏偏與公主長(zhǎng)得像吸奴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348