Java注解全解析

什么是注解?

Annontation(注解)是Java5開始引入的新特征。它提供了一種安全的類似注釋的機(jī)制,用來(lái)將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類、方法、成員變量等)進(jìn)行關(guān)聯(lián)。與類、接口、枚舉是在同一個(gè)層次,可以理解為java 的一個(gè)類型。Java中的類、方法、變量、參數(shù)、包都可以被注解;

Java中常見的注解

@Override:我們常常見到,表示覆蓋活重寫了父類的方法;
@deprecated: 表示該方法已經(jīng)過(guò)時(shí)了,我們?cè)陂_發(fā)時(shí)有時(shí)用到某個(gè)類的方法時(shí),該方法會(huì)被橫線劃掉,說(shuō)明該方法時(shí)添加了@deprecated注解的,方法已過(guò)時(shí),不建議使用;
@SuppressWarnings:表示忽略警告,比如我們?cè)谟玫缴鲜鲞^(guò)時(shí)的方法時(shí),編譯器會(huì)有警告,我們可以標(biāo)注該注解忽略掉編譯器的警告;

元注解

元注解是什么呢?元注解是用來(lái)注解注解的注解。哈哈,是不是很繞,其實(shí)元注解就是用來(lái)標(biāo)示、聲明普通注解的,是一種基礎(chǔ)注解,像上面我們提到的java中常見的注解,那些注解都是由元注解修飾、標(biāo)示或者聲明才決定了這些普通注解的作用的;java中的元注解有以下幾個(gè):

@Retention
Retention英文的意思是保留,當(dāng)@Retention用到注解上的時(shí)候表示該注解要保留到哪個(gè)階段,或者說(shuō)表示了注解的生命周期,它的取值如下:
RetentionPolicy.SOURCE:注解只在源碼階段保留,當(dāng)編譯器開始編譯時(shí)就會(huì)被忽略、丟棄;
RetentionPolicy.CLASS:注解被保留到編譯階段,并不會(huì)被加載進(jìn)jvm;
RetentionPolicy.RUNTIME:注解會(huì)保留到程序運(yùn)行階段,它會(huì)被加載進(jìn)jvm,并且在程序運(yùn)行時(shí)可以獲取到;

@Documented
documented是文檔的意思,所以該元注解的意思是能夠?qū)⒆⒔庵械脑匕?Javadoc 中去;

@Target
target是目標(biāo)的意思,它表示注解要作用的目標(biāo);意思就是被@Target修飾的注解就限定了使用場(chǎng)景;
@Target有以下取值:
ElementType.TYPE:類,接口(包括注解類型)或enum聲明;
ElementType.CONSTRUCTOR:構(gòu)造器聲明 ;
ElementType.FIELD:屬性、字段聲明;
ElementType.LOCAL_VARIABLE:局部變量聲明;
ElementType.METHOD:方法聲明;
ElementType.PACKAGE:包聲明;
ElementType.PARAMETER:方法內(nèi)的參數(shù)聲明;

@Inherited
inherited是繼承的意思,表示如果父類有被該元注解修飾的注解,那么允許子類繼承父類的注解;

@Repeatable
Repeatable是可重復(fù)的,所以該元注解的作用是可重復(fù)的,這個(gè)是java1.8才加進(jìn)來(lái)的,算是一個(gè)新的特性,什么樣的注解是可以重復(fù)使用的呢,例如我們定義一個(gè)職位的注解,一個(gè)人可以有很多職位,比如:即是工程師又是產(chǎn)品又是設(shè)計(jì)師等等;

注解的分類

注解按照運(yùn)行機(jī)制分類可以分為:
1、源碼注解 對(duì)應(yīng)@Retention 的 RetentionPolicy.SOURCE
2、編譯時(shí)注解 對(duì)應(yīng)@Retention 的 RetentionPolicy.CLASS
3、運(yùn)行時(shí)注解 對(duì)應(yīng)@Retention 的 RetentionPolicy.RUNTIME

自定義注解

上面講了很多注解的基礎(chǔ)知識(shí),那么注解到底是如何創(chuàng)建的呢?接下來(lái)我們就來(lái)創(chuàng)建幾個(gè)自定義注解,詳細(xì)解釋一下注解的使用;
注解通過(guò) @interface 關(guān)鍵字進(jìn)行定義,它的形式跟接口很類似,不過(guò)前面多了一個(gè) @ 符號(hào);

public @interface MyAnnotation {
    //自定義注解
}

如代碼所示,我們就定義了一個(gè)簡(jiǎn)單的注解,接下來(lái)我們就可以使用了;

@MyAnnotation
public class Person {

}

我們可以用注解來(lái)修飾任意一個(gè)類,但是這樣的注解就是一個(gè)簡(jiǎn)單的標(biāo)識(shí),沒有實(shí)際意義,接下來(lái)我們來(lái)說(shuō)一下注解的屬性;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int age();

    String name();
}

上面的注解,我們限定了其可以修飾的范圍,以及它生效的階段;還定義了兩個(gè)屬性,age和name,在使用的時(shí)候我們可以對(duì)屬性進(jìn)行賦值,賦值的方式是在注解的括號(hào)內(nèi)以 value=”” 形式,多個(gè)屬性之間用 ,隔開;

@MyAnnotation(age = 20,name = "fanbingbing")
public class Person {

}

需要注意的是,在注解中定義屬性時(shí)它的類型必須是 8 種基本數(shù)據(jù)類型外加 類、接口、注解及它們的數(shù)組。

注解中屬性可以有默認(rèn)值,默認(rèn)值需要用 default 關(guān)鍵值指定。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int age() default 0;

    String name() default "object";
}

設(shè)置了默認(rèn)值后的注解,我們可以直接用,而不用賦值,也可以賦值來(lái)覆蓋默認(rèn)值;

@MyAnnotation()
public class Person {

}

這樣的話,注解取的就是默認(rèn)值;

如果一個(gè)注解內(nèi)僅僅只有一個(gè)屬性時(shí)我們可以定義為 value,應(yīng)用這個(gè)注解時(shí)可以直接接屬性值填寫到括號(hào)內(nèi)。

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

使用

@MyAnnotation("fanbingbing")
public class Person {

}

注解的提取

前面我們講到注解的屬性賦值等操作,那么這些屬性值我們?nèi)绾蝸?lái)獲取呢?
還是以上面的為例,我們自定義一個(gè)注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int age() default 0;

    String name() default "object";
}

用來(lái)修飾一個(gè)類

@MyAnnotation(age = 20,name = "fanbingbing")
public class Person {

}

獲取注解的值

boolean isAnnotation = Person.class.isAnnotationPresent(MyAnnotation.class);
if (isAnnotation) {
     MyAnnotation myAnnotation = Person.class.getAnnotation(MyAnnotation.class);
     Log.d("Test", "age=" + myAnnotation.age());
     Log.d("Test", "name=" + myAnnotation.name());
}

控制臺(tái)輸出:


獲取注解的值

可以看出我們是通過(guò)反射來(lái)獲取注解相關(guān)的值的,這里我們介紹一下用到的幾個(gè)方法:

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

該方法用來(lái)判斷是否應(yīng)用了某個(gè)注解;

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

該方法來(lái)獲取 Annotation 對(duì)象;
或者

public Annotation[] getAnnotations() {}

該方法用來(lái)獲取類中的所有注解;

接下來(lái)我們來(lái)說(shuō)一下如何獲取一個(gè)類中成員變量和成員方法的注解;
首先我們新建一個(gè)用來(lái)注解成員變量的注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFieldAnnotation {

}

然后再定義一個(gè)用來(lái)注解方法的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethodAnnotation {

}

新建一個(gè)類,使用上述注解

@MyAnnotation(age = 20, name = "fanbingbing")
public class Person {

    @MyFieldAnnotation
    public int count;


    @MyMethodAnnotation
    public void myMethod(){

    }
}

主程序中獲取屬性和方法中的注解:

      try {
            //獲取屬性上的注解
            Field field = Person.class.getDeclaredField("count");
            MyFieldAnnotation myFieldAnnotation = field.getAnnotation(MyFieldAnnotation.class);
            Log.d("Test", "MyFieldAnnotation = " + myFieldAnnotation.annotationType().getSimpleName());

            //獲取方法上的注解
            Method method = Person.class.getDeclaredMethod("myMethod");
            MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
            Log.d("Test", "MyMethodAnnotation = " + myMethodAnnotation.annotationType().getSimpleName());

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

控制臺(tái)輸出


獲取方法和屬性注解

可以看到我們要獲取屬性和方法的注解,首先要通過(guò)反射獲取到Field和Method對(duì)象,然后通過(guò)具體的對(duì)象來(lái)獲取相應(yīng)的注解就可以了;

注解的使用場(chǎng)景

到此,我們大概已經(jīng)了解了什么是注解,已經(jīng)注解的使用和自定義注解的創(chuàng)建和獲取,那么注解到底有什么用呢,什么情況下要用到注解呢?我們來(lái)看一下java的官方文檔是如何說(shuō)明的:

注解是一系列元數(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í)候接受代碼的提取;

通過(guò)官方文檔我們可以窺探到,注解不是代碼的一部分,是用來(lái)為我們的代碼服務(wù)的,用來(lái)標(biāo)示和修飾代碼,起到輔助代碼編寫的作用;同時(shí)還可以用來(lái)生成相應(yīng)的文檔,在運(yùn)行階段還能對(duì)注解的代碼進(jìn)行提取,來(lái)幫助我們完成相應(yīng)的邏輯處理等等;
關(guān)于注解本篇就介紹到此,相信大家對(duì)注解已經(jīng)有了一定的了解和認(rèn)識(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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