Java基礎(chǔ)教程之理解Annotation詳細(xì)介紹
Java基礎(chǔ)之理解Annotation
一、概念
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ǔ)句中。
二、原理
Annotation其實(shí)是一種接口。通過(guò)Java的反射機(jī)制相關(guān)的API來(lái)訪問(wèn)annotation信息。相關(guān)類(lèi)(框架或工具中的類(lèi))根據(jù)這些信息來(lái)決定如何使用該程序元素或改變它們的行為。
annotation是不會(huì)影響程序代碼的執(zhí)行,無(wú)論annotation怎么變化,代碼都始終如一地執(zhí)行。
Java語(yǔ)言解釋器在工作時(shí)會(huì)忽略這些annotation,因此在JVM 中這些annotation是“不起作用”的,只能通過(guò)配套的工具才能對(duì)這些annontaion類(lèi)型的信息進(jìn)行訪問(wèn)和處理。
Annotation與interface的異同:
1)、Annotation類(lèi)型使用關(guān)鍵字@interface而不是interface。
這個(gè)關(guān)鍵字聲明隱含了一個(gè)信息:它是繼承了java.lang.annotation.Annotation接口,并非聲明了一個(gè)interface
2)、Annotation類(lèi)型、方法定義是獨(dú)特的、受限制的。
Annotation 類(lèi)型的方法必須聲明為無(wú)參數(shù)、無(wú)異常拋出的。這些方法定義了annotation的成員:方法名成為了成員名,而方法返回值成為了成員的類(lèi)型。而方法返回值類(lèi)型必須為primitive類(lèi)型、Class類(lèi)型、枚舉類(lèi)型、annotation類(lèi)型或者由前面類(lèi)型之一作為元素的一維數(shù)組。方法的后面可以使用 default和一個(gè)默認(rèn)數(shù)值來(lái)聲明成員的默認(rèn)值,null不能作為成員默認(rèn)值,這與我們?cè)诜莂nnotation類(lèi)型中定義方法有很大不同。
Annotation類(lèi)型和它的方法不能使用annotation類(lèi)型的參數(shù)、成員不能是generic。只有返回值類(lèi)型是Class的方法可以在annotation類(lèi)型中使用generic,因?yàn)榇朔椒軌蛴妙?lèi)轉(zhuǎn)換將各種類(lèi)型轉(zhuǎn)換為Class。
3)、Annotation類(lèi)型又與接口有著近似之處。
它們可以定義常量、靜態(tài)成員類(lèi)型(比如枚舉類(lèi)型定義)。Annotation類(lèi)型也可以如接口一般被實(shí)現(xiàn)或者繼承。
三、應(yīng)用場(chǎng)合
annotation一般作為一種輔助途徑,應(yīng)用在軟件框架或工具中,在這些工具類(lèi)中根據(jù)不同的 annontation注解信息采取不同的處理過(guò)程或改變相應(yīng)程序元素(類(lèi)、方法及成員變量等)的行為。
例如:Junit、Struts、Spring等流行工具框架中均廣泛使用了annontion。使代碼的靈活性大提高。
四、常見(jiàn)標(biāo)準(zhǔn)的Annotation
從java5版本開(kāi)始,自帶了三種標(biāo)準(zhǔn)annontation類(lèi)型,
?。?)、Override
java.lang.Override 是一個(gè)marker annotation類(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í)加一個(gè)保障性的校驗(yàn)過(guò)程。
(2)、Deprecated
Deprecated也是一種marker annotation。當(dāng)一個(gè)類(lèi)型或者類(lèi)型成員使用@Deprecated修飾的話,編譯器將不鼓勵(lì)使用這個(gè)被標(biāo)注的程序元素。所以使用這種修飾具有一定的 “延續(xù)性”:如果我們?cè)诖a中通過(guò)繼承或者覆蓋的方式使用了這個(gè)過(guò)時(shí)的類(lèi)型或者成員,雖然繼承或者覆蓋后的類(lèi)型或者成員并不是被聲明為 @Deprecated,但編譯器仍然要報(bào)警。
注意:@Deprecated這個(gè)annotation類(lèi)型和javadoc中的 @deprecated這個(gè)tag是有區(qū)別的:前者是java編譯器識(shí)別的,而后者是被javadoc工具所識(shí)別用來(lái)生成文檔(包含程序成員為什么已經(jīng)過(guò)時(shí)、它應(yīng)當(dāng)如何被禁止或者替代的描述)。
(3)、SuppressWarnings
此注解能告訴Java編譯器關(guān)閉對(duì)類(lèi)、方法及成員變量的警告。
有時(shí)編譯時(shí)會(huì)提出一些警告,對(duì)于這些警告有的隱藏著B(niǎo)ug,有的是無(wú)法避免的,對(duì)于某些不想看到的警告信息,可以通過(guò)這個(gè)注解來(lái)屏蔽。
SuppressWarning不是一個(gè)marker annotation。它有一個(gè)類(lèi)型為String[]的成員,這個(gè)成員的值為被禁止的警告名。對(duì)于javac編譯器來(lái)講,被-Xlint選項(xiàng)有效的警告名也同樣對(duì)@SuppressWarings有效,同時(shí)編譯器忽略掉無(wú)法識(shí)別的警告名。
annotation語(yǔ)法允許在annotation名后跟括號(hào),括號(hào)中是使用逗號(hào)分割的name=value對(duì)用于為annotation的成員賦值:
代碼:
@SuppressWarnings(value={"unchecked","fallthrough"}) public void lintTrap() { /* sloppy method body omitted */ }
在這個(gè)例子中SuppressWarnings annotation類(lèi)型只定義了一個(gè)單一的成員,所以只有一個(gè)簡(jiǎn)單的value={...}作為name=value對(duì)。又由于成員值是一個(gè)數(shù)組,故使用大括號(hào)來(lái)聲明數(shù)組值。
注意:我們可以在下面的情況中縮寫(xiě)annotation:當(dāng)annotation只有單一成員,并成員命名為"value="。這時(shí)可以去"value="。比如將上面的SuppressWarnings annotation進(jìn)行縮寫(xiě):
代碼:
@SuppressWarnings({"unchecked","fallthrough"})
如果SuppressWarnings所聲明的被禁止警告?zhèn)€數(shù)為一個(gè)時(shí),可以省去大括號(hào):
@SuppressWarnings("unchecked")
五、自定義annontation示例
示例共涉及四個(gè)類(lèi):
清單1:Author.java
package com.magc.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 定義作者信息,name和group * @author magc * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface Author { String name(); String group(); }
清單2:Description.java
/** * */ package com.magc.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author magc * * 定義描述信息 value */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented public @interface Description { String value(); }
清單3:Utility.java
package com.magc.annotation; @Description(value = "這是一個(gè)有用的工具類(lèi)") public class Utility { @Author(name = "haoran_202",group="com.magc") public String work() { return "work over!"; } }
注:這是個(gè)普通的Java類(lèi),運(yùn)行了@Description和@Author注解。
清單3:AnalysisAnnotation.java
package com.magc.annotation; import java.lang.reflect.Method; public class AnalysisAnnotation { /** * 在運(yùn)行時(shí)分析處理annotation類(lèi)型的信息 * * */ public static void main(String[] args) { try { //通過(guò)運(yùn)行時(shí)反射API獲得annotation信息 Class rt_class = Class.forName("com.magc.annotation.Utility"); Method[] methods = rt_class.getMethods(); boolean flag = rt_class.isAnnotationPresent(Description.class); if(flag) { Description description = (Description)rt_class.getAnnotation(Description.class); System.out.println("Utility's Description--->"+description.value()); for (Method method : methods) { if(method.isAnnotationPresent(Author.class)) { Author author = (Author)method.getAnnotation(Author.class); System.out.println("Utility's Author--->"+author.name()+" from "+author.group()); } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
注:這是個(gè)與自定義@Description和@Author配套的基礎(chǔ)框架或工具類(lèi),通過(guò)此類(lèi)來(lái)獲得與普通Java類(lèi)Utility.java關(guān)聯(lián)的信息,即描述和作者。
運(yùn)行AnalysisAnnotation,輸出結(jié)果為:
Utility's Description--->這是一個(gè)有用的工具類(lèi)
Utility's Author--->haoran_202 from com.magc
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Spring Cloud學(xué)習(xí)教程之Zuul統(tǒng)一異常處理與回退
Spring Cloud Zuul對(duì)異常的處理整體來(lái)說(shuō)還是比較方便的,流程也比較清晰,下面這篇文章主要給大家介紹了關(guān)于Spring Cloud學(xué)習(xí)教程之Zuul統(tǒng)一異常處理與回退的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04springboot+vue實(shí)現(xiàn)Token自動(dòng)續(xù)期(雙Token方案)
雙Token方案通過(guò)訪問(wèn)令牌和刷新令牌提高用戶(hù)登錄安全性和體驗(yàn),訪問(wèn)令牌有效期短,包含用戶(hù)信息,用于請(qǐng)求校驗(yàn),本文就來(lái)介紹一下springboot+vue實(shí)現(xiàn)Token自動(dòng)續(xù)期(雙Token方案),感興趣的可以了解一下2024-10-10經(jīng)典再現(xiàn) 基于JAVA平臺(tái)開(kāi)發(fā)坦克大戰(zhàn)游戲
經(jīng)典再現(xiàn),這篇文章主要介紹了基于JAVA平臺(tái)開(kāi)發(fā)坦克大戰(zhàn)游戲的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06SpringCloud學(xué)習(xí)筆記之OpenFeign進(jìn)行服務(wù)調(diào)用
OpenFeign對(duì)feign進(jìn)行進(jìn)一步的封裝,添加了springmvc的一些功能,更加強(qiáng)大,下面這篇文章主要給大家介紹了關(guān)于SpringCloud學(xué)習(xí)筆記之OpenFeign進(jìn)行服務(wù)調(diào)用的相關(guān)資料,需要的朋友可以參考下2022-01-01利用MyBatis-Plus靈活處理JSON字段的技巧與最佳實(shí)踐
這篇文章主要給大家介紹了關(guān)于利用MyBatis-Plus靈活處理JSON字段的技巧與最佳實(shí)踐,Mybatis-Plus可以很方便地處理JSON字段,在實(shí)體類(lèi)中可以使用@JSONField注解來(lái)標(biāo)記JSON字段,需要的朋友可以參考下2024-07-07Servlet實(shí)現(xiàn)共享數(shù)據(jù)JavaWeb組件的幾種方法
本文將結(jié)合實(shí)例代碼,介紹Servlet實(shí)現(xiàn)共享數(shù)據(jù)JavaWeb組件的幾種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07springboot接口如何多次獲取request中的body內(nèi)容
這篇文章主要介紹了springboot接口多次獲取request中的body內(nèi)容的過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06springboot實(shí)現(xiàn)異步任務(wù)
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)異步任務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05關(guān)于SpringSecurity簡(jiǎn)介以及和Shiro的區(qū)別
這篇文章主要介紹了關(guān)于SpringSecurity簡(jiǎn)介以及和Shiro的區(qū)別,在Java應(yīng)用安全領(lǐng)域,Spring Security會(huì)成為被首先推崇的解決方案,就像我們看到服務(wù)器就會(huì)聯(lián)想到Linux一樣順理成章,需要的朋友可以參考下2023-07-07