十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
這篇文章給大家介紹Java中Annotation注解的作用是什么,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
十余年的肥鄉(xiāng)網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整肥鄉(xiāng)建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“肥鄉(xiāng)網(wǎng)站設(shè)計(jì)”,“肥鄉(xiāng)網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
我們?cè)谄綍r(shí)的開發(fā)過程中看到很多如@Override,@SuppressWarnings,@Test等樣式的代碼就是注解,注解是放到類、構(gòu)造器、方法、屬性、參數(shù)前的標(biāo)記。
給某個(gè)類、方法..添加了一個(gè)注解,這個(gè)環(huán)節(jié)僅僅是做了一個(gè)標(biāo)記,對(duì)代碼本身并不會(huì)造成任何影響,需要后續(xù)環(huán)節(jié)的配合,需要其他方法對(duì)該注解賦予業(yè)務(wù)邏輯處理。就如同我們?cè)谖⑿派习l(fā)了一個(gè)共享定位,此時(shí)并沒有什么用,只有當(dāng)后面其他人都進(jìn)入了這個(gè)共享定位,大家之間的距離才能明確,才知道該怎么聚在一起。
注解分為三類:
如@Override,@SuppressWarnings都是編譯器使用到的注解,作用是告訴編譯器一些事情,而不會(huì)進(jìn)入編譯后的.class文件。
@Override:告訴編譯器檢查一下是否重寫了父類的方法;
@SuppressWarnings:告訴編譯器忽略該段代碼產(chǎn)生的警告;
對(duì)于開發(fā)人員來說,都是直接使用,無需進(jìn)行其他操作
需要通過工具對(duì).class字節(jié)碼文件進(jìn)行修改的一些注解,某些工具會(huì)在類加載的時(shí)候,動(dòng)態(tài)修改用某注解標(biāo)注的.class文件,從而實(shí)現(xiàn)一些特殊的功能,一次性處理完成后,并不會(huì)存在于內(nèi)存中,都是非常底層的工具庫、框架會(huì)使用,對(duì)于開發(fā)人員來說,一般不會(huì)涉及到。
一直存在于JVM中,在運(yùn)行期間可以讀取的注解,也是最常用的注解,如Spring的@Controller,@Service,@Repository,@AutoWired,Mybatis的@Mapper,Junit的@Test等,這類注解很多都是工具框架自定義在運(yùn)行期間發(fā)揮特殊作用的注解,一般開發(fā)人員也可以自定義這類注解。
我們使用@interface來定義一個(gè)注解
/** * 定義一個(gè)Table注解 */ public @interface Table { String value() default ""; } /** * 定義一個(gè)Colum注解 */ public @interface Colum { String value() default ""; String name() default ""; String dictType() default ""; }
這樣就簡(jiǎn)單地將一個(gè)注解定義好了
我們上面定義的注解主要用到了String類型,但實(shí)際上還可以是基本數(shù)據(jù)類型(不能為包裝類)、枚舉類型。
注解也有一個(gè)約定俗成的東西,最常用的參數(shù)應(yīng)該命名為value,同時(shí)一般情況下我們都會(huì)通過default參數(shù)設(shè)置一個(gè)默認(rèn)值。
但這樣是不是就滿足于我們的使用了呢,我想把@Table
注解僅用于類上,@Colum
注解僅用于屬性上,怎么辦?而且開始提到的三類注解,一般開發(fā)人員用的都是運(yùn)行期的注解,那我們定義的是嗎?
要回答這些問題,就需要引入一個(gè)概念“元注解”。
可以修飾注解的注解即為元注解,Java已經(jīng)定義了一些元注解,我們可以直接使用。
顧名思義指定注解使用的目標(biāo)對(duì)象,參數(shù)為ElementType[]
public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }
而下面是ElementType枚舉中定義的屬性,不設(shè)置Target的時(shí)候,除了TYPE_PARAMETER,TYPE_USE,其他地方都相當(dāng)于配置上了。
public enum ElementType { /** 通過ElementType.TYPE可以修飾類、接口、枚舉 */ TYPE, /** 通過ElementType.FIELD可以修飾類屬性 */ FIELD, /** 通過ElementType.METHOD可以修飾方法 */ METHOD, /** 通過ElementType.PARAMETER可以修飾參數(shù)(如構(gòu)造器或者方法中的) */ PARAMETER, /** 通過ElementType.CONSTRUCTOR可以修改構(gòu)造器 */ CONSTRUCTOR, /** 通過ElementType.LOCAL_VARIABLE可以修飾方法內(nèi)部的局部變量 */ LOCAL_VARIABLE, /** 通過ElementType.ANNOTATION_TYPE可以修飾注解 */ ANNOTATION_TYPE, /** 通過ElementType.PACKAGE可以修飾包 */ PACKAGE, /** * 可以用在Type的聲明式前 * * @since 1.8 */ TYPE_PARAMETER, /** * 可以用在所有使用Type的地方(如泛型、類型轉(zhuǎn)換等) * * @since 1.8 */ TYPE_USE }
我們主要說一下ElementType.PACKAGE和1.8添加的ElementType.TYPE_PARAMETER和ElementType.TYPE_USE
ElementType.PACKAGE
@Target(ElementType.PACKAGE) public @interface Table { String value() default ""; }
含義是用來修飾包,但我們用來修飾包的時(shí)候卻提示錯(cuò)誤
我們按照提示創(chuàng)建package-info.java文件,這里需要注意一下,通過IDE 進(jìn)行new --> Java Class是創(chuàng)建不了的,需要通過new File文件創(chuàng)建
@Table package annotation; class PackageInfo { public void hello() { System.out.println("hello"); } }
ElementType.TYPE_PARAMETER和ElementType.TYPE_USE
這兩個(gè)一起說,因?yàn)樗鼈冇邢嗨浦?。都是Java1.8后添加的
@Target(ElementType.TYPE_USE) public @interface NoneEmpty { String value() default ""; } @Target(ElementType.TYPE_PARAMETER) public @interface NoneBlank { String value() default ""; }
很明顯使用ElementType.TYPE_PARMETER修飾的注解@NoneBlank無法在泛型使用的時(shí)候編譯通過,僅能用于類的泛型聲明,而通過ElementType.TYPE_USE修飾的注解@NoneEmpty可以。
可以用于定義注解的生命周期,參數(shù)為枚舉RetentionPolicy,包括了SOURCE,CLASS,RUNTIME
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); } public enum RetentionPolicy { /** * 僅存在于源代碼中,編譯階段會(huì)被丟棄,不會(huì)包含于class字節(jié)碼文件中. */ SOURCE, /** * 【默認(rèn)策略】,在class字節(jié)碼文件中存在,在類加載的時(shí)被丟棄,運(yùn)行時(shí)無法獲取到 */ CLASS, /** * 始終不會(huì)丟棄,可以使用反射獲得該注解的信息。自定義的注解最常用的使用方式。 */ RUNTIME }
表示是否將此注解的相關(guān)信息添加到j(luò)avadoc文檔中
定義該注解和子類的關(guān)系,使用此注解聲明出來的自定義注解,在使用在類上面時(shí),子類會(huì)自動(dòng)繼承此注解,否則,子類不會(huì)繼承此注解。注意,使用@Inherited聲明出來的注解,只有在類上使用時(shí)才會(huì)有效,對(duì)方法,屬性等其他無效。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface Person { String value() default "man"; } @Person public class Parent { } //子類也擁有@Person注解 class Son extends Parent { }
用@interface定義注解
可以添加多個(gè)參數(shù),核心參數(shù)按約定用value,為每個(gè)參數(shù)可以設(shè)置默認(rèn)值,參數(shù)類型包括基本類型、String和枚舉
可以使用元注解來修飾注解,元注解包括多個(gè),必須設(shè)置@Target
和@Retention
,@Retention
一般設(shè)置為RUNTIME
。
我們前面已經(jīng)提到光配置了注解,其實(shí)沒有作用,需要通過相應(yīng)的代碼來實(shí)現(xiàn)該注解想要表達(dá)的邏輯。
注解定義后也是一種class,所有的注解都繼承自java.lang.annotation.Annotation
,因此,讀取注解,需要使用反射API。
//定義的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Colum { String value() default ""; //用于表示某個(gè)屬性代表的中文含義 String name() default ""; }
用注解@Colum來修飾某個(gè)類的屬性
public class Person { @Colum(name = "姓名") private String name; @Colum(name = "性別") private String gender; @Colum(name = "年齡") private int age; @Colum(name = "住址") private String address; public String getName() {return name;} public void setName(String name) {this.name = name;} public String getGender() {return gender;} public void setGender(String gender) {this.gender = gender;} public int getAge() {return age;} public void setAge(int age) {this.age = age;} public String getAddress() {return address;} public void setAddress(String address) {this.address = address;} }
通過反射讀取這個(gè)類的所有字段的中文含義,并保存到list中,然后打印出來
public static void main(String[] args) throws ClassNotFoundException { ListcolumNames = new ArrayList<>(); Class clazz = Class.forName("annotation.Person"); //獲取Person類所有屬性 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields){ //獲取該屬性的Colum注解 Colum colum = field.getAnnotation(Colum.class); //或者可以先判斷有無該注解 field.isAnnotationPresent(Colum.class); //將該屬性通過注解配置好的中文含義取出來放到集合中 columNames.add(colum.name()); } //打印集合 columNames.forEach((columName) -> System.out.println(columName)); }
結(jié)果如下:
姓名 性別 年齡 住址
比如我們有一些常見的應(yīng)用場(chǎng)景,需要把網(wǎng)站上的列表導(dǎo)出成excel表格,我們通過注解的方式把列名配置好,再通過反射讀取實(shí)體需要導(dǎo)出(是否需要導(dǎo)出,也可通過注解配置)的每個(gè)字段的值,從而實(shí)現(xiàn)excel導(dǎo)出的組件。
本文只是拋磚引玉地講解了注解的基本概念,注解的作用,幾種元注解的功用以及使用方法,并通過一個(gè)簡(jiǎn)單的例子講解了一下注解的處理,并不全面,文中通過Field講解了注解的基本Api,但注解還可以修飾類、構(gòu)造器、方法等,也有相對(duì)應(yīng)的注解處理方法,大家可自行查一下API手冊(cè)相關(guān)內(nèi)容,大同小異,有不對(duì)之處,請(qǐng)批評(píng)指正,望共同進(jìn)步,謝謝!
關(guān)于Java中Annotation注解的作用是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。