理解Java注解

關(guān)于注解

定義:注解(Annotation),也叫元數(shù)據(jù)。一種代碼級(jí)別的說明。它是JDK1.5及以后版本引入的一個(gè)特性,與類、接口、枚舉是在同一個(gè)層次。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對(duì)這些元素進(jìn)行說明,注釋。

作用分類:

①編寫文檔:通過代碼里標(biāo)識(shí)的元數(shù)據(jù)生成文檔【生成文檔doc文檔】

② 代碼分析:通過代碼里標(biāo)識(shí)的元數(shù)據(jù)對(duì)代碼進(jìn)行分析【使用反射】

③編譯檢查:通過代碼里標(biāo)識(shí)的元數(shù)據(jù)讓編譯器能夠?qū)崿F(xiàn)基本的編譯檢查【Override】

Annotation(注解)是JDK1.5及以后版本引入的。它可以用于創(chuàng)建文檔,跟蹤代碼中的依賴性,甚至執(zhí)行基本編譯時(shí)檢查。注解是以‘@注解名’在代碼中存在的,根據(jù)注解參數(shù)的個(gè)數(shù),我們可以將注解分為:標(biāo)記注解、單值注解、完整注解三類。它們都不會(huì)直接影響到程序的語義,只是作為注解(標(biāo)識(shí))存在,我們可以通過反射機(jī)制編程實(shí)現(xiàn)對(duì)這些元數(shù)據(jù)(用來描述數(shù)據(jù)的數(shù)據(jù))的訪問。另外,你可以在編譯時(shí)選擇代碼里的注解是否只存在于源代碼級(jí),或者它也能在class文件、或者運(yùn)行時(shí)中出現(xiàn)(SOURCE/CLASS/RUNTIME)。(來自百度)


元注解

基本內(nèi)置注解

@Override

它的作用是對(duì)覆蓋超類中方法的方法進(jìn)行標(biāo)記,如果被標(biāo)記的方法并沒有實(shí)際覆蓋超類中的方法,則編譯器會(huì)發(fā)出錯(cuò)誤警告。

public?class?OverrideDemoTest?{

????@Override

????public?String?tostring()?{

????????return?"測試注解";

????}

}

@Deprecated

它的作用是對(duì)不應(yīng)該再使用的方法添加注解,當(dāng)編程人員使用這些方法時(shí),將會(huì)在編譯時(shí)顯示提示信息,它與javadoc里的@deprecated標(biāo)記有相同的功能,準(zhǔn)確的說,它還不如javadoc @deprecated,因?yàn)樗恢С謪?shù),使用@Deprecated的示例代碼示例如下:

public?class?DeprecatedDemoTest?{

????public?static?void?main(String[]args)?{

????????//?使用DeprecatedClass里聲明被過時(shí)的方法

????????DeprecatedClass.DeprecatedMethod();

????}

}


class?DeprecatedClass?{

????@Deprecated

????public?static?void?DeprecatedMethod()?{

????}

}

@SuppressWarnings

其參數(shù)有:

deprecation,使用了過時(shí)的類或方法時(shí)的警告

unchecked,執(zhí)行了未檢查的轉(zhuǎn)換時(shí)的警告

fallthrough,當(dāng) switch 程序塊直接通往下一種情況而沒有 break 時(shí)的警告

path,在類路徑、源文件路徑等中有不存在的路徑時(shí)的警告

serial,當(dāng)在可序列化的類上缺少serialVersionUID 定義時(shí)的警告

finally ,任何 finally 子句不能正常完成時(shí)的警告

all,關(guān)于以上所有情況的警告

public?class?SuppressWarningsDemoTest?{

????@SuppressWarnings("unchecked")

????public?void?say(String?str)?{

????}

}


自定義注解

它類似于新創(chuàng)建一個(gè)接口文件,但為了區(qū)分,我們需要將它聲明為@interface

public?@interface?TestAnnotation?{

}

使用自定義的注解類型

public?class?AnnotationTest?{

????@TestAnnotation

????public?static?void?main(String[]args)?{

????}

}

為自定義注解添加變量? 變量說明:

第一,只能用public或默認(rèn)(default)這兩個(gè)訪問權(quán)修飾.例如,String value();這里把方法設(shè)為defaul默認(rèn)類型.

第二,參數(shù)成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據(jù)類型和String,Enum,Class,annotations等數(shù)據(jù)類型,以及這一些類型的數(shù)組.例如,String value();這里的參數(shù)成員就為String.

第三,如果只有一個(gè)參數(shù)成員,最好把參數(shù)名稱設(shè)為"value",后加小括號(hào).例:上面的例子就只有一個(gè)參數(shù)成員.

public?@interface?NewAnnotation?{

????String?value();

}

public?class?AnnotationTest?{

????@TestAnnotation("mainmethod")

????public?static?void?main(String[]args)?{

????????say();

????}

????@TestAnnotation(value="一個(gè)外地的招呼")

????public?static?void?say()?{

????}

}

定義一個(gè)枚舉類型,然后將參數(shù)設(shè)置為該枚舉類型,并賦予默認(rèn)值

public?@interface?ColorBox{

????public?enum?BOX {

????????BLUE,

????????RED,

????????GREEN

????};

????String?name();

????BOX box()?default?BOX.RED;

}

這里有兩種選擇,其實(shí)變數(shù)也就是在賦予默認(rèn)值的參數(shù)上,我們可以選擇使用該默認(rèn)值

也可以重新設(shè)置一個(gè)值來替換默認(rèn)值

public?class?AnnotationTest?{

????@TestAnnotation("mainmethod")

????public?static?void?main(String[]args)?{

????????say();

????????defaultColor();

????????dedColor();

????}


????@TestAnnotation("來自外地的招呼")

????public?static?void?say()?{

????}


????//?此時(shí)的fontColor為默認(rèn)的RED

????@ColorBox(name="defaultfontcolor")

????public?static?void?defaultColor()?{

????}


????//?將box改為BLUE

????@ColorBox(name="notdefault",?box=ColorBox.BOX.BLUE)

????public?static?void?redColor()?{

????}

}

----------------------------------------------

注解高級(jí)應(yīng)用

使用范圍

用@Target指定ElementType屬性

public?enum?ElementType?{

????//?用于類,接口,枚舉但不能是注解??TYPE,

????//?字段上,包括枚舉值???FIELD,

????//?方法,不包括構(gòu)造方法????METHOD,

????//?方法的參數(shù)????PARAMETER,

????//?構(gòu)造方法????CONSTRUCTOR,

????//?本地變量或catch語句????LOCAL_VARIABLE,

????//?注解類型(無數(shù)據(jù))????ANNOTATION_TYPE,

????//?Java包????PACKAGE

}

具體例子:

//?限制注解使用范圍

@Target({ElementType.METHOD,ElementType.CONSTRUCTOR})

public?@interface?ColorBox{

????//?使用枚舉類型

????public?enum?Box{

????????BLUE,RED,GREEN

????};

????String?name();

????Box box()?default?Box.RED;

}

注解保持性策略

在Java編譯器編譯時(shí),它會(huì)識(shí)別在源代碼里添加的注解是否還會(huì)保留,這就是RetentionPolicy。下面是Java定義的RetentionPolicy枚舉:

編譯器的處理有三種策略:

將注解保留在編譯后的類文件中,并在第一次加載類時(shí)讀取它;

將注解保留在編譯后的類文件中,但是在運(yùn)行時(shí)忽略它;

按照規(guī)定使用注解,但是并不將它保留到編譯后的類文件中。

public?enum?RetentionPolicy?{

????//?此類型會(huì)被編譯器丟棄????SOURCE,

????//?此類型注解會(huì)保留在class文件中,但JVM會(huì)忽略它????CLASS,

????//?此類型注解會(huì)保留在class文件中,JVM會(huì)讀取它???RUNTIME

}

//?讓保持性策略為運(yùn)行時(shí)態(tài),即將注解編碼到class文件中,讓虛擬機(jī)讀取

@Retention(RetentionPolicy.RUNTIME)

public?@interface?ColorBox{

????//?使用枚舉類型

????public?enum?Box{

????????BLUE,RED,GREEN

????};

????String?name();

????Box box()?default?Box.RED;

}

文檔化功能

Java提供的Documented元注解跟Javadoc的作用是差不多的,其實(shí)它存在的好處是開發(fā)人員可以定制Javadoc不支持的文檔屬性

并在開發(fā)中應(yīng)用。它的使用跟前兩個(gè)也是一樣的,簡單代碼示例如下:

//?讓它定制文檔化功能

//?使用此注解時(shí)必須設(shè)置RetentionPolicy為RUNTIME

@Documented

public?@interface?ColorBox{

????//?使用枚舉類型

????public?enum?Box{

????????BLUE,RED,GREEN

????};

????String?name();

????Box box()?default?Box.RED;

}

標(biāo)注繼承

//?讓它允許繼承,可作用到子類

@Inherited

public?@interface?ColorBox{

????//?使用枚舉類型

????public?enum?Box{

????????BLUE,RED,GREEN

????};

????String?name();

????Box box()?default?Box.RED;

}

------------------------------------------------------------------

讀取方法

屬于重點(diǎn),在系統(tǒng)中用到注解權(quán)限時(shí)非常有用,可以精確控制權(quán)限的粒度

注意:要想使用反射去讀取注解,必須將Retention的值選為Runtime

import?java.lang.annotation.Annotation;

import?java.lang.reflect.Method;

//讀取注解信息

public?class?ReadAnnotationInfoTest?{

????public?static?void?main(String[]?args)?throws?Exception?{

????????//?測試AnnotationTest類,得到此類的類對(duì)象

????????Class?c?=?Class.forName("com.iwtxokhtd.annotation.AnnotationTest");

????????//?獲取該類所有聲明的方法

????????Method[]?methods?=?c.getDeclaredMethods();

????????//?聲明注解集合

????????Annotation[]?annotations;

????????//?遍歷所有的方法得到各方法上面的注解信息

????????for?(Method?method?:?methods)?{

????????????//?獲取每個(gè)方法上面所聲明的所有注解信息

????????????annotations?=?method.getDeclaredAnnotations();

????????????//?再遍歷所有的注解,打印其基本信息

????????????System.out.println(method.getName());

????????????for?(Annotation?an?:?annotations)?{

????????????????System.out.println("方法名為:"?+?method.getName()?+?"其上面的注解為:"?+?an.annotationType().getSimpleName());

????????????????Method[]?meths?=?an.annotationType().getDeclaredMethods();

????????????????//?遍歷每個(gè)注解的所有變量

????????????????for?(Method?meth?:?meths)?{

????????????????????System.out.println("注解的變量名為:"?+?meth.getName());

????????????????}

????????????}

????????}

????}

}

Class?c?=?Class.forName("com.iwtxokhtd.annotation.AnnotationTest");

boolean flag = c.isAnnotationPresent(Description.class);

????????if (flag) {

????????????// 得到 Description? 的描述

????????????Description des = (Description) c.getAnnotation(Description.class);

????????????System.out.println("描述:" + des.value());

????????}

// 把某個(gè)引用指定注解的類有利用到@(具體注解的類名)的全部方法保存到Set中去???????

?Set set = new HashSet();

Method[] method = c.getMethods();

????????for (int i = 0; i < method.length; i++) {

????????????boolean otherFlag = method[i].isAnnotationPresent(注解類名.class);

????????????if (otherFlag)

????????????????set.add(method[i]);

????????}

然后就可以遍歷set獲取注解的設(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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