<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          注解知識掃盲

          共 5654字,需瀏覽 12分鐘

           ·

          2021-10-22 14:48

          一、注解

          1.1 概述

          注解(Annotation)在JDK1.5之后增加的一個新特性,注解的引入意義很大,有很多非常有名的框架,比如Hibernate、Spring等框架中都大量使用注解。注解作為程序的元數(shù)據(jù)嵌入到程序。注解可以被解析工具或編譯工具解析,此處注意注解不同于注釋(comment)。

          當(dāng)一個接口直接繼承java.lang.annotation.Annotation接口時,仍是接口,而并非注解。要想自定義注解類型,只能通過@interface關(guān)鍵字的方式,其實通過該方式會隱含地繼承.Annotation接口。

          1.2 API 摘要

          所有與Annotation相關(guān)的API摘要如下:

          (1). 注解類型(Annotation Types) API

          注解類型含義
          Documented表示含有該注解類型的元素(帶有注釋的)會通過javadoc或類似工具進(jìn)行文檔化
          Inherited表示注解類型能被自動繼承
          Retention表示注解類型的存活時長
          Target表示注解類型所適用的程序元素的種類

          (2). 枚舉(Enum) API

          枚舉含義
          ElementType程序元素類型,用于Target注解類型
          RetentionPolicy注解保留策略,用于Retention注解類型

          (3). 異常和錯誤 API

          異常/錯誤含義
          AnnotationTypeMismatchException當(dāng)注解經(jīng)過編譯(或序列化)后,注解類型改變的情況下,程序視圖訪問該注解所對應(yīng)的元素,則拋出此異常
          IncompleteAnnotationException當(dāng)注解經(jīng)過編譯(或序列化)后,將其添加到注解類型定義的情況下,程序視圖訪問該注解所對應(yīng)的元素,則拋出此異常。
          AnnotationFormatError當(dāng)注解解析器試圖從類文件中讀取注解并確定注解出現(xiàn)異常時,拋出該錯誤

          二、注解類型

          前面講到注解類型共4種,分別為Documented、Inherited、Retention、Target,接下來從jdk1.7的源碼角度,來分別加以說明:

          2.1 Documented

          源碼:

          1@Documented
          2@Retention(RetentionPolicy.RUNTIME)
          3@Target(ElementType.ANNOTATION_TYPE)
          4public?@interface?Documented?{
          5}

          @Documented:表示擁有該注解的元素可通過javadoc此類的工具進(jìn)行文檔化。該類型應(yīng)用于注解那些影響客戶使用帶注釋(comment)的元素聲明的類型。如果類型聲明是用Documented來注解的,這種類型的注解被作為被標(biāo)注的程序成員的公共API。

          例如,上面源碼@Retention的定義中有一行@Documented,意思是指當(dāng)前注解的元素會被javadoc工具進(jìn)行文檔化,那么在查看Java API文檔時可查看該注解元素。

          2.2 Inherited

          源碼:

          1@Documented
          2@Retention(RetentionPolicy.RUNTIME)
          3@Target(ElementType.ANNOTATION_TYPE)
          4public?@interface?Inherited?{
          5}

          @Inherited:表示該注解類型被自動繼承,如果用戶在當(dāng)前類中查詢這個元注解類型并且當(dāng)前類的聲明中不包含這個元注解類型,那么也將自動查詢當(dāng)前類的父類是否存在Inherited元注解,這個動作將被重復(fù)執(zhí)行知道這個標(biāo)注類型被找到,或者是查詢到頂層的父類。

          2.3 Retention

          源碼:

          1@Documented
          2@Retention(RetentionPolicy.RUNTIME)
          3@Target(ElementType.ANNOTATION_TYPE)
          4public?@interface?Retention?{
          5????RetentionPolicy?value();
          6}

          @Retention:表示該注解類型的注解保留的時長。當(dāng)注解類型聲明中沒有@Retention元注解,則默認(rèn)保留策略為RetentionPolicy.CLASS。關(guān)于保留策略(RetentionPolicy)是枚舉類型,共定義3種保留策略,如下表:

          RetentionPolicy含義
          SOURCE僅存在Java源文件,經(jīng)過編譯器后便丟棄相應(yīng)的注解
          CLASS存在Java源文件,以及經(jīng)編譯器后生成的Class字節(jié)碼文件,但在運(yùn)行時VM不再保留注釋
          RUNTIME存在源文件、編譯生成的Class字節(jié)碼文件,以及保留在運(yùn)行時VM中,可通過反射性地讀取注解

          例如,上面源碼@Retention的定義中有一行@Retention(RetentionPolicy.RUNTIME),意思是指當(dāng)前注解的保留策略為RUNTIME,即存在Java源文件,也存在經(jīng)過編譯器編譯后的生成的Class字節(jié)碼文件,同時在運(yùn)行時虛擬機(jī)(VM)中也保留該注解,可通過反射機(jī)制獲取當(dāng)前注解內(nèi)容。

          2.4 Target

          源碼:

          1@Documented
          2@Retention(RetentionPolicy.RUNTIME)
          3@Target(ElementType.ANNOTATION_TYPE)
          4public?@interface?Target?{
          5????ElementType[]?value();
          6}

          @Target:表示該注解類型的所使用的程序元素類型。當(dāng)注解類型聲明中沒有@Target元注解,則默認(rèn)為可適用所有的程序元素。如果存在指定的@Target元注解,則編譯器強(qiáng)制實施相應(yīng)的使用限制。關(guān)于程序元素(ElementType)是枚舉類型,共定義8種程序元素,如下表:

          ElementType含義
          ANNOTATION_TYPE注解類型聲明
          CONSTRUCTOR構(gòu)造方法聲明
          FIELD字段聲明(包括枚舉常量)
          LOCAL_VARIABLE局部變量聲明
          METHOD方法聲明
          PACKAGE包聲明
          PARAMETER參數(shù)聲明
          TYPE類、接口(包括注解類型)或枚舉聲明

          例如,上面源碼@Target的定義中有一行@Target(ElementType.ANNOTATION_TYPE),意思是指當(dāng)前注解的元素類型是注解類型。

          三、內(nèi)建注解

          Java提供了多種內(nèi)建的注解,下面接下幾個比較常用的注解:@Override、@Deprecated、@SuppressWarnings這3個注解。

          3.1 @Override(覆寫)

          源碼:

          1@Target(ElementType.METHOD)
          2@Retention(RetentionPolicy.SOURCE)
          3public?@interface?Override?{
          4}

          用途:用于告知編譯器,我們需要覆寫超類的當(dāng)前方法。如果某個方法帶有該注解但并沒有覆寫超類相應(yīng)的方法,則編譯器會生成一條錯誤信息。

          注解類型分析:@Override可適用元素為方法,僅僅保留在java源文件中。

          3.2 @Deprecated(不贊成使用)

          源碼:

          1@Documented
          2@Retention(RetentionPolicy.RUNTIME)
          3@Target(value={CONSTRUCTOR,?FIELD,?LOCAL_VARIABLE,?METHOD,?PACKAGE,?PARAMETER,?TYPE})
          4public?@interface?Deprecated?{
          5}

          用途:用于告知編譯器,某一程序元素(比如方法,成員變量)不建議使用時,應(yīng)該使用這個注解。Java在javadoc中推薦使用該注解,一般應(yīng)該提供為什么該方法不推薦使用以及相應(yīng)替代方法。

          注解類型分析:@Deprecated可適合用于除注解類型聲明之外的所有元素,保留時長為運(yùn)行時VM。

          3.3 @SuppressWarnings(壓制警告)

          源碼:

          1@Target({TYPE,?FIELD,?METHOD,?PARAMETER,?CONSTRUCTOR,?LOCAL_VARIABLE})
          2@Retention(RetentionPolicy.SOURCE)
          3public?@interface?SuppressWarnings?{
          4????String[]?value();
          5}

          用于:用于告知編譯器忽略特定的警告信息,例在泛型中使用原生數(shù)據(jù)類型。

          注解類型分析:@SuppressWarnings可適合用于除注解類型聲明和包名之外的所有元素,僅僅保留在java源文件中。

          該注解有方法value(),可支持多個字符串參數(shù),例如:

          1@SupressWarning(value={"uncheck","deprecation"})?

          前面講的@Override,@Deprecated都是無需參數(shù)的,而壓制警告是需要帶有參數(shù)的,可用參數(shù)如下:

          參數(shù)含義
          deprecation使用了過時的類或方法時的警告
          unchecked執(zhí)行了未檢查的轉(zhuǎn)換時的警告
          fallthrough當(dāng)Switch程序塊進(jìn)入進(jìn)入下一個case而沒有Break時的警告
          path在類路徑、源文件路徑等有不存在路徑時的警告
          serial當(dāng)可序列化的類缺少serialVersionUID定義時的警告
          finally任意finally子句不能正常完成時的警告
          all以上所有情況的警告

          3.4 對比

          3種內(nèi)建注解的對比:

          內(nèi)建注解TargetRetention
          OverrideMETHODSOURCE
          SuppressWarnings除ANNOTATION_TYPE和PACKAGE外的所有SOURCE
          Deprecated除ANNOTATION_TYPE外的所有RUNTIME

          四、 實戰(zhàn)

          4.1 自定義注解

          創(chuàng)建自定義注解,與創(chuàng)建接口有幾分相似,但注解需要以@開頭,下面先聲明一個自定義注解(AuthorAnno.java)文件:

           1package?com.test.annotation;
          2import?java.lang.annotation.Documented;
          3import?java.lang.annotation.ElementType;
          4import?java.lang.annotation.Inherited;
          5import?java.lang.annotation.Retention;
          6import?java.lang.annotation.RetentionPolicy;
          7import?java.lang.annotation.Target;
          8
          9@Documented
          10@Target(ElementType.METHOD)
          11@Inherited
          12@Retention(RetentionPolicy.RUNTIME)
          13public?@interface?AuthorAnno{
          14????String?name();
          15????String?website()?default?"gityuan.com";
          16????int?revision()?default?1;
          17}

          自定義注解規(guī)則:

          1. 注解方法不帶參數(shù),比如name()website()

          2. 注解方法返回值類型:基本類型、String、Enums、Annotation以及前面這些類型的數(shù)組類型

          3. 注解方法可有默認(rèn)值,比如default "gityuan.com",默認(rèn)website=”gityuan.com”

          有了前面的自定義注解@AuthorAnno,那么我們便可以在代碼中使用(AnnotationDemo.java),如下:

           1package?com.test.annotation;
          2
          3public?class?AnnotationDemo?{
          4????@AuthorAnno(name="yuanhh",?website="gityuan.com",?revision=1)
          5????public?static?void?main(String[]?args)?{
          6????????System.out.println("I?am?main?method");
          7????}
          8
          9????@SuppressWarnings({?"unchecked",?"deprecation"?})
          10????@AuthorAnno(name="yuanhh",?website="gityuan.com",?revision=2)
          11????public?void?demo(){
          12????????System.out.println("I?am?demo?method");
          13????}
          14}

          由于該注解的保留策略為RetentionPolicy.RUNTIME,故可在運(yùn)行期通過反射機(jī)制來使用,否則無法通過反射機(jī)制來獲取。

          4.2 注解解析

          接下來,通過反射技術(shù)來解析自定義注解@AuthorAnno,關(guān)于反射類位于包java.lang.reflect,其中有一個接口AnnotatedElement,該接口定義了注釋相關(guān)的幾個核心方法,如下:

          返回值方法解釋
          TgetAnnotation(Class?annotationClass)當(dāng)存在該元素的指定類型注解,則返回相應(yīng)注釋,否則返回null
          Annotation[]getAnnotations()返回此元素上存在的所有注解
          Annotation[]getDeclaredAnnotations()返回直接存在于此元素上的所有注解。
          booleanisAnnotationPresent(Class annotationClass)當(dāng)存在該元素的指定類型注解,則返回true,否則返回false

          前面自定義的注解,適用對象為Method。類Method繼承類AccessibleObject,而類AccessibleObject實現(xiàn)了AnnotatedElement接口,那么可以利用上面的反射方法,來實現(xiàn)解析@AuthorAnno的功能(AnnotationParser.java),內(nèi)容如下:

           1package?com.test.annotation;
          2import?java.lang.reflect.Method;
          3
          4public?class?AnnotationParser?{
          5????public?static?void?main(String[]?args)?throws?SecurityException,?ClassNotFoundException?{
          6????????String?clazz?=?"com.yuanhh.annotation.AnnotationDemo";
          7????????Method[]??demoMethod?=?AnnotationParser.class
          8????????????????.getClassLoader().loadClass(clazz).getMethods();
          9
          10????????for?(Method?method?:?demoMethod)?{
          11????????????if?(method.isAnnotationPresent(AuthorAnno.class))?{
          12?????????????????AuthorAnno?authorInfo?=?method.getAnnotation(AuthorAnno.class);
          13?????????????????System.out.println("method:?"+?method);
          14?????????????????System.out.println("name=?"+?authorInfo.name()?+?
          15?????????????????????????"?,?website=?"+?authorInfo.website()
          16????????????????????????+?"?,?revision=?"+authorInfo.revision());
          17????????????}
          18????????}
          19????}
          20}

          程序運(yùn)行的輸出結(jié)果:

          1method:?public?void?com.yuanhh.annotation.AnnotationDemo.demo()
          2name=?yuanhh?,?website=?gityuan.com?,?revision=?2
          3method:?public?static?void?com.yuanhh.annotation.AnnotationDemo.main(java.lang.String[])
          4name=?yuanhh?,?website=?gityuan.com?,?revision=?1

          這里通過反射將注解直接輸出只是出于demo,完全可以根據(jù)拿到的注解信息做更多有意義的事。

          source: //yuanfentiank789.github.io/2016/01/23/java-annotation

          喜歡,在看


          瀏覽 59
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩免费A∨ | 1级毛片特黄色 | 中文字幕亚洲视频在线观看 | 国产三级黄片 | 日韩精品国产无码 |