Java註解又稱Java標註,是Java語言5.0版本開始支持加入源代碼的特殊語法元數據。Java語言中的類、方法、變量、參數和包等均可以被標註。和Javadoc不一樣,Java標註能夠經過反射獲取標註內容。在編譯器生成類文件時,標註能夠被嵌入到字節碼中。Java虛擬機能夠保留標註內容,在運行時能夠獲取到標註內容。html
維基百科對java註解說的仍是比較到位了,不理解能夠先看看後面,再回來看上面的定義就很清楚了。java
@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
Retention 的英文意爲保留期的意思。當 @Retention 應用到一個註解上的時候,它解釋說明了這個註解的的存活時間。spa
它有一下三種取值:
使用場景:這類註解提供信息給編譯器,編譯器能夠利用註解來探測錯誤和警告信息,好比咱們的
@Override
使用場景:軟件工具能夠利用註解信息來生成代碼,Html文檔和作其餘相應處理。
使用場景:能夠獲取到它們的信息並進行邏輯處理(這也是咱們常常用的,會配合反射使用)。
大概示例圖以下:
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}) // 只能註解到屬性、方法,包上。
複製代碼
標記註解,沒有成員,顧名思義,這個元註解確定是和文檔有關。它的做用是可以將註解中的元素包含到 Javadoc 中去。
參考 Annotation深刻研究——@Documented註釋使用
Inherited
是繼承的意思,可是它並非說註解自己能夠繼承,而是說若是一個超類被 @Inherited 註解過的註解進行註解的話,那麼若是它的子類沒有被任何註解應用的話,那麼這個子類就繼承了超類的註解。
下面簡單經過一個Demo來演示一下:
@Inherited
元註解Human
類,使用咱們自定義註解@Test
Man
類繼承至Human
類。@Test
註解Man
類也能獲取到@Test
註解和參數,這就是由於其父類上的註解使用了@Inherited
元註解字面意思是可重複的,說明這個元註解可重複使用,咱們看到@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 = {175, 65})
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> A 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,下一篇見!