Java註解基礎介紹及使用

Java註解基礎介紹及使用

1、什麼是註解

一、官方定義

Java註解又稱Java標註,是Java語言5.0版本開始支持加入源代碼的特殊語法元數據。Java語言中的類、方法、變量、參數和包等均可以被標註。和Javadoc不一樣,Java標註能夠經過反射獲取標註內容。在編譯器生成類文件時,標註能夠被嵌入到字節碼中。Java虛擬機能夠保留標註內容,在運行時能夠獲取到標註內容。html

維基百科對java註解說的仍是比較到位了,不理解能夠先看看後面,再回來看上面的定義就很清楚了。java

二、通俗說法


在Android中,註解的使用無處不在,好比上圖中的 @Override@Nullable,註解實際就是添加在類、變量、方法、參數等前面的一個修飾符而已,能夠理解成一個標籤。

註解和註釋不同,註釋只能保留在源碼階段,用來對代碼的解釋或者說明,能夠看作就是文本,可是註解不同,它能夠保留到運行階段,咱們能夠把註解也理解成代碼,註釋性代碼,它除了提供了對代碼的解釋說明,它還能跟代碼同樣提供功能操做,但它是被動性的,就是它能提供信息,可是須要咱們經過其餘方式來獲取,好比能夠經過其餘方式如反射在動態運行階段獲取註解的信息並使用。web

三、註解怎麼寫?

咱們直接點 @Override 註解進去看看就知道,一個註解是什麼定義的。數組

這是@Override 註解的寫法,先無論A和B,這個咱們後面會說,直接先看D,一個註解,須要使用 @interface,就跟咱們的類須要用class修飾,接口用interface修飾同樣,只要用@interface修飾的就是註解。app

因此,一個簡單的註解能夠以下定義。ide

1public @interface TestAnnotation {}
複製代碼

使用:
函數

四、元註解

再看上圖,還有A@Target 和B@Retention兩個「註解」,這種用來註解註解的註解咱們叫作元註解,若是註解理解成是一個標籤的話,那麼元註解就是比較特殊的標籤,它只能用來對普通標籤進行解釋說明。工具

元註解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 種。post

4.一、@Retention

Retention 的英文意爲保留期的意思。當 @Retention 應用到一個註解上的時候,它解釋說明了這個註解的的存活時間。spa

它有一下三種取值:

  • RetentionPolicy.SOURCE :
    註解只在源碼階段保留,在編譯器進行編譯時它將被丟棄忽視。

使用場景:這類註解提供信息給編譯器,編譯器能夠利用註解來探測錯誤和警告信息,好比咱們的 @Override

  • RetentionPolicy.CLASS :
    註解只被保留到編譯進行的時候,它並不會被加載到 JVM 中。

使用場景:軟件工具能夠利用註解信息來生成代碼,Html文檔和作其餘相應處理。

  • RetentionPolicy.RUNTIME :
    註解能夠保留到程序運行的時候,它會被加載進入到 JVM 中,因此在程序運行時

使用場景:能夠獲取到它們的信息並進行邏輯處理(這也是咱們常常用的,會配合反射使用)。

大概示例圖以下:

4.二、@Target

Target 英語就是目標的意思, @Target 指定了註解能夠運用的地方,咱們前面說了註解能夠用在類、方法、變量、參數和包等上面,若是咱們沒有使用 @Target 元註解對註解進行解釋說明,那麼這個註解能夠隨意放在類、方法變量這些地方,咱們使用了 @Target後 ,經過指定其能夠運用的地方,規定其只能用在咱們指定的上。

@Target 參數是一個數組枚舉 ElementType[]

 1public enum ElementType {
2    /** Class, interface (including annotation type), or enum declaration */
3    TYPE,  //  接口、類、枚舉、註解
4
5    /** Field declaration (includes enum constants) */
6    FIELD, // 字段、屬性、枚舉的常量
7
8    /** Method declaration */
9    METHOD, // 方法
10
11    /** Formal parameter declaration */
12    PARAMETER,// 方法參數
13
14    /** Constructor declaration */
15    CONSTRUCTOR, //構造函數
16
17    /** Local variable declaration */
18    LOCAL_VARIABLE, //局部變量
19
20    /** Annotation type declaration */
21    ANNOTATION_TYPE, //註解
22
23    /** Package declaration */
24    PACKAGE, //包   
25
26    /**
27     * Type parameter declaration
28     *
29     * @since 1.8
30     */

31    TYPE_PARAMETER,
32
33    /**
34     * Use of a type
35     *
36     * @since 1.8
37     */

38    TYPE_USE
39}
複製代碼

使用:

1@Target(ElementType.FIELD) // 只能註解到一個屬性上。
複製代碼
1@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PACKAGE}) // 只能註解到屬性、方法,包上。
複製代碼
4.三、@Documented

標記註解,沒有成員,顧名思義,這個元註解確定是和文檔有關。它的做用是可以將註解中的元素包含到 Javadoc 中去。

參考 Annotation深刻研究——@Documented註釋使用

4.四、@Inherited

Inherited 是繼承的意思,可是它並非說註解自己能夠繼承,而是說若是一個超類被 @Inherited 註解過的註解進行註解的話,那麼若是它的子類沒有被任何註解應用的話,那麼這個子類就繼承了超類的註解。

下面簡單經過一個Demo來演示一下:

  • 首先定義一個註解,並使用@Inherited元註解
  • 定義一個Human類,使用咱們自定義註解@Test
  • 新建一個Man類繼承至Human類。
  • 咱們在Man類中經過反射獲取其是否也擁有@Test註解
  • 從結果能夠看出來,在Man類也能獲取到@Test註解和參數,這就是由於其父類上的註解使用了@Inherited元註解
4.五、@Repeatable

字面意思是可重複的,說明這個元註解可重複使用,咱們看到@Repeatable註解的變量類型則是對應Annotation(接口)的泛型Class。

  • 咱們先定義一個重複註解類:

  • 再聲明一個容器註解類

  • 咱們就能夠對@Tag註解重複使用,能夠看到沒有使用@Repeatable的註解重複使用就會報錯

註解的屬性

經過前面的示例咱們能夠看到,咱們能夠爲咱們的註解添加屬性,註解的屬性也叫作成員變量。註解只有成員變量,沒有方法。

註解的成員變量在註解的定義中以「無形參的方法」形式來聲明,

其方法名定義了該成員變量的名字,其返回值定義了該成員變量的類型

反射中,經過getDeclaredMethod來獲取。

在註解中定義屬性時它的類型必須是 8 種基本數據類型外加 類、接口、註解及它們的數組
註解中屬性能夠有默認值,默認值須要用 default 關鍵值指定。

前面基本已經演示過了,咱們仍是簡單演示一下。

定義一個帶有多個成員變量的註解:

 1/**
2 * @author : EvanZch
3 *         description:定義多個成員變量註解
4 **/

5
6@Target(ElementType.TYPE)
7@Retention(RetentionPolicy.RUNTIME)
8public @interface TestValueAnnotation {
9    String name() default "EvanZch";
10
11    int age();
12
13    int[] info();
14}
複製代碼

使用:

1@TestValueAnnotation(name = "Evan", age = 18, info = {17565})
2public class AnnotationValueTest {
3
4    public static void main(String[] args) {
5    }
6
7}
複製代碼

註解提取

註解一般與反射一塊兒使用,而反射就是在運行狀態中,對於任意一個類,都能知道這個類的全部屬性及方法,對於任何一個對象,都能調用他的任何一個方法和屬性,這種動態獲取新的及動態調用對象的方法的功能叫作反射.

對反射不熟悉的能夠先看看Java反射以及在Android中的使用

註解經過反射獲取。首先能夠經過 Class 對象的 isAnnotationPresent() 方法判斷它是否應用了某個註解

1public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
複製代碼

而後經過 getAnnotation() 方法來獲取 Annotation 對象。

1 public <A extends Annotation> getAnnotation(Class<A> annotationClass) {}
複製代碼

或者是 getAnnotations() 方法。

1public Annotation[] getAnnotations() {}
複製代碼

前一種方法返回指定類型的註解,後一種方法返回註解到這個元素上的全部註解。

咱們經過前面的AnnotationValueTest類演示,獲取AnnotationValueTest類上@TestValueAnnotation註解的信息。

  • 註釋儘量的詳細了,若是還不清楚能夠先去看看反射。
 1public static void main(String[] args) {
2// 1、判斷AnnotationValueTest類上是否有註解
3// 一、先拿到AnnotationValueTest的class對象
4        Class<?> annotationValueTestzz = AnnotationValueTest.class;
5 // 二、經過其class對象調用isAnnotationPresent進行判斷
6        boolean isAnnotation = annotationValueTestzz.isAnnotationPresent(TestValueAnnotation.class);
7        System.out.println("AnnotationValueTest--isAnnotation=" + isAnnotation);
8// 若是有註解
9if (isAnnotation) {
10// 三、有註解拿到這個註解的Annotation對象
11       TestValueAnnotation annotation = annotationValueTestzz.getAnnotation(TestValueAnnotation.class);
12 // 四、經過annotation對象獲取其成員變量
13            int age = annotation.age();
14            int[] infos = annotation.info();
15            String name = annotation.name();
16            System.out.println("AnnotationValueTest--age=" + age + ",info.length=" + infos.length + ",name=" + name);
17  }
複製代碼

結果:


能夠看到,咱們成功判斷到 AnnotationValueTest類上的 @TestValueAnnotation註解中的全部屬性信息。

總結

關於註解的使用,在Android中很常見,好比咱們butterknife和retrofit庫裏面就大量使用註解來進行操做,咱們下一篇,經過一篇註解實戰來寫一個簡易版本的butterknife,下一篇見!

相關文章
相關標籤/搜索