1.注解概念
1)什么是注解:
對(duì)于很多初次接觸的開(kāi)發(fā)者來(lái)說(shuō)應(yīng)該都有這個(gè)疑問(wèn)晒屎?Annontation是Java5開(kāi)始引入的新特征量愧,中文名稱(chēng)叫注解柑土。它提供了一種安全的類(lèi)似注釋的機(jī)制慢哈,用來(lái)將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類(lèi)榛斯、方法观游、成員變量等)進(jìn)行關(guān)聯(lián)。為程序的元素(類(lèi)驮俗、方法懂缕、成員變量)加上更直觀更明了的說(shuō)明,這些說(shuō)明信息是與程序的業(yè)務(wù)邏輯無(wú)關(guān)王凑,并且供指定的工具或框架使用搪柑。Annontation像一種修飾符一樣,應(yīng)用于包索烹、類(lèi)型工碾、構(gòu)造方法、方法百姓、成員變量渊额、參數(shù)及本地變量的聲明語(yǔ)句中。
總結(jié)來(lái)說(shuō):
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)建文檔矗晃,跟蹤代碼中的依賴(lài)性,甚至執(zhí)行基本編譯時(shí)檢查宴倍。從某些方面看张症,annotation就像修飾符一樣被使用,并應(yīng)用于包鸵贬、類(lèi) 型俗他、構(gòu)造方法、方法阔逼、成員變量兆衅、參數(shù)、本地變量的聲明中嗜浮。
Annotation能被用來(lái)為某個(gè)程序元素(類(lèi)羡亩、方法、成員變量等)關(guān)聯(lián)任何的信息危融。需要注意的是畏铆,這里存在著一個(gè)基本的規(guī)則:Annotation不能影響程序代碼的執(zhí)行,無(wú)論增加吉殃、刪除 Annotation辞居,代碼都始終如一的執(zhí)行。另外蛋勺,盡管一些annotation通過(guò)java的反射api方法在運(yùn)行時(shí)被訪問(wèn)瓦灶,而java語(yǔ)言解釋器在工作時(shí)忽略了這些annotation。正是由于java虛擬機(jī)忽略了Annotation抱完,導(dǎo)致了annotation類(lèi)型在代碼中是“不起作用”的贼陶; 只有通過(guò)某種配套的工具才會(huì)對(duì)annotation類(lèi)型中的信息進(jìn)行訪問(wèn)和處理。
2)什么是metadata(元數(shù)據(jù))
元數(shù)據(jù)是指用來(lái)描述數(shù)據(jù)的數(shù)據(jù)乾蛤,更通俗一點(diǎn)每界,就是描述代碼間關(guān)系捅僵,或者代碼與其他資源(例如數(shù)據(jù)庫(kù)表)之間內(nèi)在聯(lián)系的數(shù)據(jù)家卖。元數(shù)據(jù)的功能作用有很多,比如:你可能用過(guò)Javadoc的注釋自動(dòng)生成文檔庙楚。這就是元數(shù)據(jù)功能的一種上荡。總的來(lái)說(shuō),元數(shù)據(jù)可以用來(lái)創(chuàng)建文檔酪捡,跟蹤代碼的依賴(lài)性叁征,執(zhí)行編譯時(shí)格式檢查,代替已有的配置文件逛薇。
在Java中元數(shù)據(jù)以標(biāo)簽的形式存在于Java代碼中捺疼,元數(shù)據(jù)標(biāo)簽的存在并不影響程序代碼的編譯和執(zhí)行,它只是被用來(lái)生成其它的文件或針在運(yùn)行時(shí)知道被運(yùn)行代碼的描述信息永罚。
綜上所述:
第一啤呼,元數(shù)據(jù)以標(biāo)簽的形式存在于Java代碼中。
第二呢袱,元數(shù)據(jù)描述的信息是類(lèi)型安全的官扣,即元數(shù)據(jù)內(nèi)部的字段都是有明確類(lèi)型的。
第三羞福,元數(shù)據(jù)需要編譯器之外的工具額外的處理用來(lái)生成其它的程序部件惕蹄。
第四,元數(shù)據(jù)可以只存在于Java源代碼級(jí)別治专,也可以存在于編譯之后的Class文件內(nèi)部卖陵。
2.注解分類(lèi):
1)系統(tǒng)內(nèi)置標(biāo)準(zhǔn)注解:
a.Override,限定重寫(xiě)父類(lèi)方法
@Override 是一個(gè)標(biāo)記注解類(lèi)型看靠,它被用作標(biāo)注方法赶促。它說(shuō)明了被標(biāo)注的方法重載了父類(lèi)的方法,起到了斷言的作用挟炬。如果我們使用了這種Annotation在一個(gè)沒(méi)有覆蓋父類(lèi)方法的方法時(shí)鸥滨,java編譯器將以一個(gè)編譯錯(cuò)誤來(lái)警示。這個(gè)annotaton常常在我們?cè)噲D覆蓋父類(lèi)方法而確又寫(xiě)錯(cuò)了方法名時(shí)發(fā)揮威力谤祖。使用方法極其簡(jiǎn)單:在使用此annotation時(shí)只要在被修飾的方法前面加上@Override即可婿滓。
這里我們定義了一個(gè)父類(lèi)father 里面定義了一個(gè)方法getName,定義了一個(gè)son類(lèi)粥喜,里面復(fù)寫(xiě)了父類(lèi)的getName方法并用Override凸主,限定重寫(xiě)父類(lèi)方法
b.@Deprecated,標(biāo)記已過(guò)時(shí):
同 樣Deprecated也是一個(gè)標(biāo)記注解额湘。當(dāng)一個(gè)類(lèi)型或者類(lèi)型成員使用@Deprecated修飾的話(huà)卿吐,編譯器將不鼓勵(lì)使用這個(gè)被標(biāo)注的程序元素。而且這種修飾具有一定的 “延續(xù)性”:如果我們?cè)诖a中通過(guò)繼承或者覆蓋的方式使用了這個(gè)過(guò)時(shí)的類(lèi)型或者成員锋华,雖然繼承或者覆蓋后的類(lèi)型或者成員并不是被聲明為 @Deprecated嗡官,但編譯器仍然要報(bào)警。
這里我們看下代碼:定義了一個(gè)ParentDeprecated毯焕,并把他標(biāo)記為過(guò)時(shí)Deprecated衍腥,然后我們就能發(fā)現(xiàn)ide工具在他的類(lèi)名上劃了一條橫線,而且當(dāng)我定義他的子類(lèi)childDeprecated時(shí),發(fā)現(xiàn)在她的類(lèi)名前也會(huì)被表明過(guò)時(shí)婆咸。
最后竹捉,值得注意,@Deprecated這個(gè)annotation類(lèi)型和javadoc中的 @deprecated這個(gè)tag是有區(qū)別的:前者是java編譯器識(shí)別的尚骄,而后者是被javadoc工具所識(shí)別用來(lái)生成文檔(包含程序成員為什么已經(jīng)過(guò) 時(shí)块差、它應(yīng)當(dāng)如何被禁止或者替代的描述)。
c.SuppressWarnnings倔丈,抑制編譯器警告:
@SuppressWarnings 被用于有選擇的關(guān)閉編譯器對(duì)類(lèi)憾儒、方法、成員變量乃沙、變量初始化的警告起趾。在java5.0,sun提供的javac編譯器為我們提供了-Xlint選項(xiàng)來(lái)使編譯器對(duì)合法的程序代碼提出警告警儒,此種警告從某種程度上代表了程序錯(cuò)誤训裆。例如當(dāng)我們使用一個(gè)generic collection類(lèi)而又沒(méi)有提供它的類(lèi)型時(shí),編譯器將提示出"unchecked warning"的警告蜀铲。通常當(dāng)這種情況發(fā)生時(shí)边琉,我們就需要查找引起警告的代碼。如果它真的表示錯(cuò)誤记劝,我們就需要糾正它变姨。例如如果警告信息表明我們代碼中的switch語(yǔ)句沒(méi)有覆蓋所有可能的case,那么我們就應(yīng)增加一個(gè)默認(rèn)的case來(lái)避免這種警告厌丑。
有時(shí)我們無(wú)法避免這種警告定欧,例如,我們使用必須和非generic的舊代碼交互的generic collection類(lèi)時(shí)怒竿,我們不能避免這個(gè)unchecked warning砍鸠。此時(shí)@SuppressWarning就要派上用場(chǎng)了,在調(diào)用的方法前增加@SuppressWarnings修飾耕驰,告訴編譯器停止對(duì)此方法的警告爷辱。
SuppressWarnings注解的常見(jiàn)參數(shù)值的簡(jiǎn)單說(shuō)明:
1.deprecation:使用了不贊成使用的類(lèi)或方法時(shí)的警告;
2.unchecked:執(zhí)行了未檢查的轉(zhuǎn)換時(shí)的警告朦肘,例如當(dāng)使用集合時(shí)沒(méi)有用泛型 (Generics) 來(lái)指定集合保存的類(lèi)型;
當(dāng)我們不使用@SuppressWarnings注釋時(shí)饭弓,編譯器就會(huì)有如下提示:
注意:SuppressWarningsDemo.java 使用了未經(jīng)檢查或不安全的操作。
注意:要了解詳細(xì)信息媒抠,請(qǐng)使用 -Xlint:unchecked 重新編譯弟断。
SuppressWarnings 被用于有選擇的關(guān)閉編譯器對(duì)類(lèi)、方法领舰、成員變量夫嗓、變量初始化的警告
2)元注解:元注解的作用就是負(fù)責(zé)注解其他注解。Java5.0定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類(lèi)型冲秽,它們被用來(lái)提供對(duì)其它 annotation類(lèi)型作說(shuō)明舍咖。
a.@Target:
@Target說(shuō)明了Annotation所修飾的對(duì)象范圍:Annotation可被用于 packages、types(類(lèi)锉桑、接口排霉、枚舉、Annotation類(lèi)型)民轴、類(lèi)型成員(方法攻柠、構(gòu)造方法、成員變量后裸、枚舉值)瑰钮、方法參數(shù)和本地變量(如循環(huán)變量、catch參數(shù))微驶。在Annotation類(lèi)型的聲明中使用了target可更加明晰其修飾的目標(biāo)浪谴。
取值(ElementType)有:
1.CONSTRUCTOR:用于描述構(gòu)造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部變量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述參數(shù)
7.TYPE:用于描述類(lèi)、接口(包括注解類(lèi)型) 或enum聲明
看table這個(gè)類(lèi):注解Table 可以用于注解類(lèi)因苹、接口(包括注解類(lèi)型) 或enum聲明,而注解NoDBColumn僅可用于注解類(lèi)的成員變量苟耻。
b.@Retention:
@Retention定義了該Annotation被保留的時(shí)間長(zhǎng)短:某些Annotation僅出現(xiàn)在源代碼中,而被編譯器丟棄扶檐;而另一些卻被編譯在class文件中凶杖;編譯在class文件中的Annotation可能會(huì)被虛擬機(jī)忽略,而另一些在class被裝載時(shí)將被讀瓤钪(請(qǐng)注意并不影響class的執(zhí)行智蝠,因?yàn)锳nnotation與class在使用上是被分離的)。使用這個(gè)meta-Annotation可以對(duì) Annotation的“生命周期”限制奈梳。
作用:表示需要在什么級(jí)別保存該注釋信息寻咒,用于描述注解的生命周期(即:被描述的注解在什么范圍內(nèi)有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)
看Column這個(gè)類(lèi):Column注解的的RetentionPolicy的屬性值是RUTIME,這樣注解處理器可以通過(guò)反射,獲取到該注解的屬性值颈嚼,從而去做一些運(yùn)行時(shí)的邏輯處理
c.@Documented:
@Documented用于描述其它類(lèi)型的annotation應(yīng)該被作為被標(biāo)注的程序成員的公共API毛秘,因此可以被例如javadoc此類(lèi)的工具文檔化。Documented是一個(gè)標(biāo)記注解阻课,沒(méi)有成員
我們可以在上面那個(gè)類(lèi)中添加@Documented
d.@Inherited:
@Inherited 元注解是一個(gè)標(biāo)記注解叫挟,@Inherited闡述了某個(gè)被標(biāo)注的類(lèi)型是被繼承的。如果一個(gè)使用了@Inherited修飾的annotation類(lèi)型被用于一個(gè)class限煞,則這個(gè)annotation將被用于該class的子類(lèi)抹恳。
看Greeting這個(gè)類(lèi)表明這個(gè)類(lèi)型時(shí)被繼承的
3.Android support annotations
Android support library從19.1版本開(kāi)始引入了一個(gè)新的注解庫(kù),它包含很多有用的元注解署驻,你能用它們修飾你的代碼奋献,幫助你發(fā)現(xiàn)bug健霹。Support library自己本身也用到了這些注解,所以作為support library的用戶(hù)瓶蚂,Android Studio已經(jīng)基于這些注解校驗(yàn)了你的代碼并且標(biāo)注其中潛在的問(wèn)題糖埋。
注解默認(rèn)是沒(méi)有包含的;它被包裝成一個(gè)獨(dú)立的庫(kù)窃这,如果使用了appcompat庫(kù)瞳别,那么Support Annotations就會(huì)自動(dòng)引入進(jìn)來(lái),因?yàn)閍ppcompat使用了Support Annotations杭攻,如果沒(méi)有則需要在build.gradle中添加配置
分類(lèi):
1)Nullness注解
@NonNull注解可以用來(lái)標(biāo)識(shí)特定的參數(shù)或者返回值不可以為null
由于代碼中參數(shù)String s使用@NonNull注解修飾祟敛,因此IDE將會(huì)以警告的形式提醒我們這個(gè)地方有問(wèn)題:
如果我們給name賦值,例如String name = “Our Lord Duarte”兆解,那么警告將消失馆铁。
使用@Nullable注解修飾的函數(shù)參數(shù)或者返回值可以為null。假設(shè)User類(lèi)有一個(gè)名為name的變量锅睛,使用User.getName()訪問(wèn)叼架,
因?yàn)間etName函數(shù)的返回值使用@Nullable修飾,所以調(diào)用:toast的時(shí)候沒(méi)有檢查getName的返回值是否為空衣撬,將可能導(dǎo)致crash乖订。
2)Resource Type 注解
資源在Android中作為整型值來(lái)傳遞。這意味著希望獲取一個(gè)drawable作為參數(shù)的代碼很容易被傳遞了一個(gè)string類(lèi)型的資源具练,因?yàn)樗麄冑Y源id都是整型的乍构,編譯器很難區(qū)分。Resource Type注解在這種條件下可以提供類(lèi)型檢查
是否曾經(jīng)傳遞了錯(cuò)誤的資源整型值給函數(shù)扛点,還能夠愉快的得到本來(lái)想要的整型值嗎哥遮?資源類(lèi)型注解可以幫助我們準(zhǔn)確實(shí)現(xiàn)這一點(diǎn)。在下面的代碼中陵究,我們的testStringRes函數(shù)預(yù)期接受一個(gè)字符串類(lèi)型的id眠饮,并使用@StringRes注解修飾:
3)Threading 注解
比如我們?cè)陧?xiàng)目中處理比較耗時(shí)的操作,需要制定在工作子線程中執(zhí)行铜邮,可以使用Threading 注解仪召,如果沒(méi)有在制定的線程中執(zhí)行也是編譯不過(guò)的
幾種Threading注解
@UiThread UI線程
@MainThread 主線程
@WorkerThread 子線程
@BinderThread 綁定線程
4)Overriding Methods 注解: @CallSuper
如果你的API允許使用者重寫(xiě)你的方法,但是呢松蒜,你又需要你自己的方法(父方法)在重寫(xiě)的時(shí)候也被調(diào)用扔茅,這時(shí)候你可以使用@CallSuper標(biāo)注
看代碼
5.總結(jié):
Annotation翻譯為中文即為注解,意思就是提供除了程序本身邏輯外的額外的數(shù)據(jù)信息秸苗。Annotation對(duì)于標(biāo)注的代碼沒(méi)有直接的影響召娜,它不可以直接與標(biāo)注的代碼產(chǎn)生交互,但其他組件可以使用這些信息惊楼。
Annotation信息可以被編譯進(jìn)class文件玖瘸,也可以保留在Java 虛擬機(jī)中秸讹,從而在運(yùn)行時(shí)可以獲取。甚至對(duì)于Annotation本身也可以加Annotation雅倒。
注解是如何被處理的:
當(dāng)Java源代碼被編譯時(shí)璃诀,編譯器的一個(gè)插件annotation處理器則會(huì)處理這些annotation。處理器可以產(chǎn)生報(bào)告信息屯断,或者創(chuàng)建附加的Java源文件或資源。如果annotation本身被加上了RententionPolicy的運(yùn)行時(shí)類(lèi)侣诺,則Java編譯器則會(huì)將annotation的元數(shù)據(jù)存儲(chǔ)到class文件中殖演。然后,Java虛擬機(jī)或其他的程序可以查找這些元數(shù)據(jù)并做相應(yīng)的處理年鸳。當(dāng)然除了annotation處理器可以處理annotation外趴久,我們也可以使用反射自己來(lái)處理annotation
作者: DocMike
鏈接:https://www.imooc.com/article/19158
來(lái)源:慕課網(wǎng)