Android 注解--(一)注解基礎(chǔ)

學(xué)習(xí)注解原理的理由
越來(lái)越多的Android庫(kù)中使用的注解,比如butterknife,EventBus3,okHttp里面也是使用了注解,減少了重復(fù)代碼的編寫(xiě),極大的方便我們快速開(kāi)發(fā),那么了解其內(nèi)部的工作原理極其重要,而且如果我們不知道其中的原理,我們?cè)谑褂眠^(guò)程中遇到的相關(guān)問(wèn)題就會(huì)一頭霧水,難以解決,所以我決定寫(xiě)一個(gè)注解Annotation的系列文章,窺探注解之秘。

注解(Annotation)是什么?
Annotation是元數(shù)據(jù)的一種形式,向外提供程序的信息,但它本身并不是這個(gè)程序的一部分,它可以被添加到包,類,方法,變量中,并且可以在某個(gè)生命周期中(java源碼中,編譯期,Runtime)被反射獲取。Annotation并不是直接影響它所注解的代碼 。

簡(jiǎn)單來(lái)說(shuō),注解(Annotation) 為我們?cè)诖a中添加信息提供了一種形式化的方法,是我們可以在稍后某個(gè)時(shí)刻方便地使用這些數(shù)據(jù)(通過(guò) 解析注解 來(lái)使用這些數(shù)據(jù))

注解(Annotation)用來(lái)做什么?
1.給編譯器提供信息--例如提供給編譯器探測(cè)錯(cuò)誤和壓制警告等等
2.編譯期生成代碼
3.運(yùn)行期(Runtime)處理注解

自定義注解
新建一個(gè)java library的module,新建一個(gè)class

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface SourceAnnotation {
    String value() default "SourceAnnotation";
}

先講一下元注解的概念,用來(lái)注解注解類的注解就是元注解,java提供了五種元注解,分別是@Documented,@Inherited, @Repeatable, @Target, @Retention

@Documented 它代表著此注解的元素會(huì)被javadoc工具提取成文檔

@Inherited 允許子類繼承父類中的注解

@Repeatable Java SE8引入的注解,表示這個(gè)注解可以在同一處多次聲明

@Target 是用來(lái)描述該注解標(biāo)記哪一種類型在java源碼中,它的取值可為:

ElementType.ANNOTATION_TYPE 可以使用在注解類型上
ElementType.CONSTRUCTOR 可以使用在構(gòu)造方法上
ElementType.FIELD 可以使用在屬性(成員變量)上
ElementType.LOCAL_VARIABLE 可以使用在局部變量上
ElementType.METHOD 可以使用在方法上
ElementType.PACKAGE 可以使用在包聲明上
ElementType.PARAMETER 可以使用在方法參數(shù)上
ElementType.TYPE 可以使用在類中任何元素

@Retention代表這個(gè)注解的生命周期,可以存活到什么時(shí)期:

RetentionPolicy.SOURCE 存在在java源碼中
RetentionPolicy.CLASS 存活到編譯成Class中
RetentionPolicy.RUNTIME 存活到運(yùn)行時(shí)期

接下來(lái)重點(diǎn)理解一下這個(gè)Rentention,我們新建一個(gè)AnnotationClass的類,然后用上面定義的SourceAnnotation去注解它

@SourceAnnotation()
public class AnnotationClass {
}

編譯一下,



然后在build文件夾classes中查找到AnnotationClass.class文件查看


package com.example;

public class AnnotationClass {
    public AnnotationClass() {
    }
}

我們的注解@SourceAnnotation()已經(jīng)不存在了,這個(gè)就是RetentionPolicy.SOURCE的作用,使注解僅存在與java源碼中。
我接下來(lái)再定義一個(gè)注解,設(shè)置為RetentionPolicy.CLASS

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ClassAnnotation {
    public String value() default "ClassAnnotation";
}

同樣,我們來(lái)注解一下AnnotationClass

@ClassAnnotation()
public class AnnotationClass {
}

編譯,查找AnnotationClass.class文件

@ClassAnnotation
public class AnnotationClass {
    public AnnotationClass() {
    }
}

發(fā)現(xiàn)我們@ClassAnnotation的注解還是存在的。

最后,我們使用RetentionPolicy.RUNTIME,新建

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RuntimeAnnotation {
    String value() default "RuntimeAnnotation";
}

注解AnnotationClass,編譯,猜想一下,是不是一樣存在?

@RuntimeAnnotation
public class AnnotationClass {
    public AnnotationClass() {
    }
}

是的,同在編譯成Class文件中可以查找到,那么RetentionPolicy.Runtime和RetentionPolicy.CLASS區(qū)別又在哪里呢?這涉及到Annotation的使用,我們上面提到,Annotation信息的獲取是通過(guò)反射獲取的,我們可以通過(guò)Class中g(shù)etAnnotation的方法來(lái)獲取接下來(lái),我們來(lái)嘗試獲取AnnationClass類中的注解信息。

注解信息的獲取
我們?cè)贏nnotationTest中,寫(xiě)一個(gè)Main方法,作為程序的入口,編寫(xiě)一下代碼

public class AnnotationTest {

    public static void main(String[] args){
        Class annotationClass = AnnotationClass.class;
        RuntimeAnnotation annotation = (RuntimeAnnotation) annotationClass.getAnnotation(RuntimeAnnotation.class);
        String value = annotation.value();
        System.out.println("value:"+value);
    }
}

我們上面定義了RuntimeAnnotation注解的默認(rèn)的值是"RuntimeAnnotion",運(yùn)行一下


查看輸出


確實(shí)打印了RuntimeAnnotion的值,說(shuō)明運(yùn)行時(shí)期獲取到這個(gè)注解的值。接下來(lái),我們獲取一下ClassAnnotation這個(gè)注解的值,看能否獲取得到,修改AnnotationClass的注解為@ClassAnnotation

@ClassAnnotation()
public class AnnotationClass {
}

修改main方法為

public class AnnotationTest {

    public static void main(String[] args){
        Class annotationClass = AnnotationClass.class;

//        RuntimeAnnotation annotation = (RuntimeAnnotation) annotationClass.getAnnotation(RuntimeAnnotation.class);
        ClassAnnotation annotation = (ClassAnnotation) annotationClass.getAnnotation(ClassAnnotation.class);

        String value = annotation.value();
        System.out.println("value:"+value);
    }
}

如果獲取得到話,應(yīng)該打印出的是默認(rèn)值"ClassAnnotation",我們運(yùn)行一下,查看輸出



我們發(fā)現(xiàn)報(bào)錯(cuò)了,而且報(bào)錯(cuò)的原因是在

String value = annotaion.value();

這一行報(bào)出空指針異常,也就是說(shuō)我們獲取ClassAnnotation這個(gè)注解不存在,我們之前看到過(guò),在編譯的class文件中,這個(gè)注解是存在的。所以這個(gè)就是RetentionPolicy.CLASS和RetentionPolicy.RUNTIME的區(qū)別,RetentionPolicy.CLASS的注解是不會(huì)存活到運(yùn)行時(shí)期的,在運(yùn)行時(shí)期要想通過(guò)反射獲得注解,那么你定義這個(gè)注解的時(shí)候需要使用RetentionPolicy.RUNTIME。

理解注解的基本使用之后,接下來(lái)我們將利用ART(Annotation Processing Tool)技術(shù)在編譯期生成代碼。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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