java注解學(xué)習(xí)

什么是注解

先舉個(gè)日常生活中的例子:在超市中有很多商品,并不是每個(gè)商品都有商標(biāo)/條形碼的,但是超市為了方便管理,給每個(gè)商品都貼了條碼,并在系統(tǒng)中存儲(chǔ)了信息,結(jié)賬時(shí)直接掃碼就行,這樣,條碼即不會(huì)對(duì)商品有影響,超市還提高了效率。

如果你明白了上面的例子,那么注解就很好理解了。你寫的代碼其實(shí)就是超市中的商品;寫的代碼是為了運(yùn)行實(shí)現(xiàn)功能,對(duì)應(yīng)的商品的意義也是實(shí)現(xiàn)價(jià)值,被購(gòu)買;為了方便商品的操作,我們對(duì)商品貼了條碼,對(duì)商品來(lái)說(shuō)沒什么影響,只是對(duì)我們、對(duì)收銀員有一個(gè)標(biāo)識(shí)的作用,對(duì)應(yīng)的就是注解。

下面引入注解的正經(jīng)說(shuō)明:

注解是插入你代碼中的一種注釋或者說(shuō)是一種元數(shù)據(jù)(meta data)。這些注解信息可以在編譯期使用預(yù)編譯工具進(jìn)行處理(pre-compiler tools)

用我的的話就是:

注解就是給你的代碼加一些解釋性的標(biāo)注,代碼該怎么跑還是怎么跑。注解的意義就是有一些工具對(duì)你的代碼進(jìn)行處理時(shí)給那些工具指明個(gè)目標(biāo)。

注解的定義

注解的定義方法

注解的定義很簡(jiǎn)單,使用 @interface關(guān)鍵字進(jìn)行定義。

注解里的屬性定義格式是 “屬性類型 屬性名+括號(hào);”,如果像加個(gè)默認(rèn)值的話就“屬性類型 屬性名+括號(hào) default 默認(rèn)值;”。

示例如下:

public @interface StudentCard{
    int id();
    String name() default "未命名";
    int level default 1;
}

使用此注解的操作如下:

//張三,學(xué)號(hào)001,卡級(jí)別10
@StudentCard(id=001,name="張三",level=10)

//名稱為“未命名”,學(xué)號(hào)002,卡級(jí)別為默認(rèn)的1
@StudentCard(id=002)

元注解

元注解就是可以注釋到注解上邊的注解,也稱為基本注解

元注解就是專門為注解定義而使用的,下面對(duì)元注解進(jìn)行羅列

@Retention

Retention英文意思是保留的意思,就是指你的注解(也就是你代碼的標(biāo)簽)保留到什么時(shí)候。是編譯時(shí)后摘了還是保存到運(yùn)行時(shí)。

取值如下:

  • RetentionPolicy.SOURCE:只在源碼階段保留,編譯之前就扔了【它的聲明周期就能接觸到編譯器了吧,一般是寫給編譯器看的】
  • RetentionPolicy.CLASS:保留到編譯階段,也就是說(shuō)編譯生成的.class文件中還有,運(yùn)行時(shí)就沒了【沒有特備聲明的話默認(rèn)就是這個(gè)選項(xiàng)】
  • RetentionPolicy.RUNTIME:在運(yùn)行階段也保留,從頭到尾都保留【可以用來(lái)反射編程】

標(biāo)記的格式如下:

@Retention(RetentionPolicy.SOURCE)

@Documented

這個(gè)標(biāo)注的意思是把這個(gè)加入javaDoc,不怎么用,至少我是沒怎么用過(guò)。

@Target

這個(gè)標(biāo)注是用來(lái)限制你定義的注解適用的對(duì)象的。

可取值如下:

  • ElementType.TYPE:表明此定義的注解可適用于類、接口(包括注解)、枚舉
  • ElementType.FIELD:表明此定義的注解可適用于類內(nèi)的變量(枚舉常量也行)
  • ElementType.METHOD:表明此定義的注解可適用于方法
  • ElementType.PARAMETER:表明此定義的注解可適用于方法傳入的參數(shù)【舉個(gè)栗子@PathVariable
  • ElementType.CONSTRUCTOR:表明此定義的注解可適用于構(gòu)造函數(shù)
  • ElementType.LOCAL_VARIABLE:表明此定義的注解可適用于局部變量
  • ElementType.ANNOTATION_TYPE:表明此定義的注解可適用于聲明的變量【什么鬼???】
  • ElementType.PACKAGE:表明此定義的注解可適用于包
  • ElementType.TYPE_PARAMETER:表明此定義的注解可適用于傳入的類型參數(shù)
  • ElementType.TYPE_USE:不清楚了,源碼的注解是 use of a type ,后面接觸到再完善吧

因?yàn)橐粋€(gè)注解可以用用在很多地方(看你想怎么用嘍),所以@Target的使用方法如下:

@Target({ElementType.PARAMETER,ElementType.LOCAL_VARIABLE,ElementType.FIELD})

@Inherited

這個(gè)注解的意思是可繼承。你寫了一個(gè)注解X,然后用X標(biāo)注了一個(gè)類A,B是A的子類,如果你定義注解時(shí)用了@Inherited標(biāo)注,那么B就等于也被注解X標(biāo)注了。

@Repeatable

這個(gè)注解的意思是是否可重復(fù)的意思,這個(gè)的使用方法有點(diǎn)復(fù)雜了,因?yàn)榭芍貜?fù)意味著你可以對(duì)一個(gè)地方打多個(gè)注解,注解的存儲(chǔ)就得用數(shù)組了,所以你得在你的注解的基礎(chǔ)上再定義一個(gè)以此注解數(shù)組為值的注解,說(shuō)的有點(diǎn)拗口,我們直接看示例代碼:

//先聲明一個(gè)注解,你要用的注解
//這里加了IdCards.class 在處理IdCard.class 注解時(shí)就放在IdCards.class的值中
@Repeatable(IdCards.class)
public @interface IdCard{
    int id() default 1;
    String name() default "未命名";
    String department() default "商城研發(fā)部";
}


//下面是IdCards.class的定義
public @interface IdCards {
    IdCard[] value();
}

IdCards.class的定義有幾個(gè)注意點(diǎn):

  1. 屬性名一定要用value
  2. 盡可能做到見名知意,知道是為誰(shuí)服務(wù)的
  3. IdCards的適用對(duì)象范圍、聲明周期范圍應(yīng)不小于IdCard的范圍

使用的時(shí)候IdCards不用使用,直接用IdCard瘋狂的重復(fù)標(biāo)注就行了

注解的使用

注解很好用,打標(biāo)簽嘛,貼上去就行了,這里主要將如何把標(biāo)簽讀出來(lái),也就是超市的掃碼過(guò)程。

注解的提取

注解通過(guò)反射提取,可以使用Class對(duì)象的方法進(jìn)行判斷是否使用了哪個(gè)注解:

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

可以通過(guò)下面的方法來(lái)獲取特定的注解的對(duì)象:

public <A extends Annotation> A getAnnotation(Class<A> annotationClass);

可以通過(guò)下面的方法獲得所有的注解對(duì)象:

public Annotation[] getAnnotations();

注解對(duì)象內(nèi)往往是私有屬性,不可達(dá),還要用一個(gè)方法來(lái)設(shè)置可達(dá)性:

Field.setAccessable(true);

附一個(gè)完整的使用的例子:

注解定義如下:

@Target({ElementType.PARAMETER,ElementType.LOCAL_VARIABLE,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Hehe {
    int intValue() default -1;
    String stringValue() default "undefinedStringValue";
    double doubleValue() default -1d;
}

注解的使用如下:

@Hehe(intValue = 200)
public class testAnnotation {
    @Hehe(stringValue = "hehe")
    private String lpc;
    public static void main(String args[]){
        testAnnotation testAnnotation = new testAnnotation();

        try{
            Field lpc = testAnnotation.getClass().getDeclaredField("lpc");
            lpc.setAccessible(true);

            Hehe hehe = lpc.getAnnotation(Hehe.class);

            if (hehe != null){
                System.out.println("變量注解中的值為: int="+ hehe.intValue());
                System.out.println("變量注解中的值為: string="+ hehe.stringValue());
                System.out.println("變量注解中的值為: double="+ hehe.doubleValue());
            }

            if ( testAnnotation.class.isAnnotationPresent(Hehe.class) ) {
                Hehe hehe1 = testAnnotation.class.getAnnotation(Hehe.class);

                System.out.println("類的注解中的值為 int="+hehe1.intValue());
            }

            try {
                Method testMethod = testAnnotation.class.getDeclaredMethod("wlgq",String.class);
                if ( testMethod != null ) {
                    // 獲取方法中的注解
                    Annotation[] ans = testMethod.getAnnotations();
                    for( int i = 0;i < ans.length;i++) {
                        System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                    }
                }

            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }



        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        System.out.println(testAnnotation.getLpc());
    }

    @Hehe(intValue=100)
    public static void wlgq(String temp){
        System.out.println(temp);
    }
    public String getLpc() {
        return lpc;
    }

    public void setLpc(String lpc) {
        this.lpc = lpc;
    }
}

獲得注解的值后就該怎么操作怎么操作唄。

注解的用法

注解是一系列元數(shù)據(jù),它提供數(shù)據(jù)用來(lái)解釋程序代碼,但是注解并非是所解釋的代碼本身的一部分。注解對(duì)于代碼的運(yùn)行效果沒有直接影響。

注解有許多用處,主要如下:
- 提供信息給編譯器: 編譯器可以利用注解來(lái)探測(cè)錯(cuò)誤和警告信息
- 編譯階段時(shí)的處理: 軟件工具可以用來(lái)利用注解信息來(lái)生成代碼、Html文檔或者做其它相應(yīng)處理。
- 運(yùn)行時(shí)的處理: 某些注解可以在程序運(yùn)行的時(shí)候接受代碼的提取

還是回到官方文檔的解釋上,注解主要針對(duì)的是編譯器和其它工具軟件(SoftWare tool)。

當(dāng)開發(fā)者使用了Annotation 修飾了類、方法、Field 等成員之后,這些 Annotation 不會(huì)自己生效,必須由開發(fā)者提供相應(yīng)的代碼來(lái)提取并處理 Annotation 信息。這些處理提取和處理 Annotation 的代碼統(tǒng)稱為 APT(Annotation Processing Tool)。

現(xiàn)在,我們可以給自己答案了,注解有什么用?給誰(shuí)用?給 編譯器或者 APT 用的。

參考文獻(xiàn)

https://blog.csdn.net/briblue/article/details/73824058 感謝大佬的作品

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java 注解 學(xué)習(xí)筆記 前言: 注解是一個(gè)很早就出現(xiàn)的技術(shù),之前一直沒有時(shí)間就這么拖著,現(xiàn)在閑暇之時(shí)學(xué)習(xí)一下,...
    真的有照片閱讀 1,155評(píng)論 0 1
  • 前言 注解(Annotation)很重要,未來(lái)的開發(fā)模式都是基于注解的,JPA是基于注解的,Spring2.5以上...
    weiinter105閱讀 319評(píng)論 0 0
  • 什么是注解 注解是 Java 5 的一個(gè)新特性。注解是插入你代碼中的一種注釋或者說(shuō)是一種元數(shù)據(jù)(meta data...
    KUN叔閱讀 583評(píng)論 0 0
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和...
    九尾喵的薛定諤閱讀 3,413評(píng)論 0 2
  • 注解的定義 官方定義:Java注解用于為Java代碼提供元數(shù)據(jù)。作為元數(shù)據(jù),注解不直接影響你的代碼執(zhí)行,但也有一些...
    crossyf閱讀 203評(píng)論 0 0

友情鏈接更多精彩內(nèi)容