Java 注解 @Annotation

同時(shí)發(fā)布于 知乎 Java 注解

1.注解的由來

在引入注解之前,在不同類型的應(yīng)用程序使用XML作為標(biāo)準(zhǔn)的代碼配置機(jī)制,程序員們描述其代碼的形式尚未標(biāo)準(zhǔn)化,每個(gè)人的做法各異:transient關(guān)鍵字、注釋、接口等,代碼和XML的解耦以及未來對(duì)這種解耦應(yīng)用的維護(hù)并不低廉,這顯然不是一種優(yōu)雅的方式,隨之而來的JDK5.0引入一種嶄新的記錄元數(shù)據(jù)的形式——注解被引入到Java中。
它的作用是修飾編程元素。什么是編程元素呢?例如:包、類、構(gòu)造方法、方法、成員變量等。

2.什么是注解

DK5.0中的類型:1、類(class)2、接口(interface)3、枚舉(enum)4、注解(Annotation)
因此,注解與其他3種類型一樣,都可以定義、使用,以及包含有自己的屬性、方法

注解分類

(1)標(biāo)記注釋:注解的內(nèi)部沒有屬性,稱作標(biāo)記注解
使用方法:@注解名
使用例子:@MarkAnnotation

(2)單值注解:注解的內(nèi)部只有一個(gè)屬性,稱作單值注解
使用方法:@注解名(屬性名=屬性值)
使用例子:@SingleAnnotation(value="abc") //也可以寫成@SingleAnnotation("abc")
*(屬性名=屬性值)可以簡(jiǎn)化為(屬性值),但是需要滿足以下兩個(gè)條件:
1、該注解必須為單值注解
2、該注解的屬性名必須為value

(3)多值注解:注解的內(nèi)部有多個(gè)屬性,稱作多值注解
使用方法:@注解名(屬性名1=屬性值1, 屬性名2=屬性值2……)
使用例子:@MultipliedAnnotation(value1 = "abc", value2 = 30……)

元注解

Java提供了一下幾個(gè)元注解(下邊會(huì)有介紹)

Target、Retention、Documented和Inherited

元注解的作用:

可以用于注解類(annotate Classes)

可以用于注解接口(annotate Interfaces)

可以用于注解枚舉類型(annotate Enums)

因此注解同樣也可以用于注解注解(annotate Annotations)

3.注解語(yǔ)法

3.1注解聲明介紹

我們通過一個(gè)簡(jiǎn)單的例子了解下:

<pre>
@Annotation
@Annotation1(info = "I am Annotation")
public AnnotationMethod(){
//代碼塊
}
</pre>

從代碼一步步看:

01.使用“@”作為前綴聲明一盒注解,向編譯器說明,該元素(Annotation)是注解

02.注解后面(),標(biāo)注它的屬性,采用鍵值對(duì)的形式,如果注解只有一個(gè)元素(或者只需要指定一個(gè)元素的值,其它則使用默認(rèn)值),也可以表示成: @Annotation("I am Annotation");如果沒有元素需要被指定,則不需要括號(hào);

03.注解用途:可以標(biāo)注在Java程序的每一個(gè)元素上使用:類,域,方法,包,變量等

3.2 預(yù)定義的注解

3.2.1 @Override

目的在于標(biāo)識(shí)某一個(gè)方法是否覆蓋了它的父類的方法

3.2.2 @Deprecated

屬于標(biāo)記注解.所謂標(biāo)記注解,就是在源程序中加入這個(gè)標(biāo)記后,并不影響程序的編譯,但有時(shí)編譯器會(huì)顯示一些警告信息。

用于標(biāo)明已經(jīng)過時(shí)的方法或類

3.2.3 @SuppressWarnnings

用于有選擇的關(guān)閉編譯器對(duì)類、方法、成員變量、變量初始化的警告.

<pre> <code>

deprecation:使用了不贊成使用的類或方法時(shí)的警告;
unchecked:執(zhí)行了未檢查的轉(zhuǎn)換時(shí)的警告,例如當(dāng)使用集合時(shí)沒有用泛型 (Generics) 來指定集合保存的類型;
fallthrough:當(dāng) Switch 程序塊直接通往下一種情況而沒有 Break 時(shí)的警告;
path:在類路徑、源文件路徑等中有不存在的路徑時(shí)的警告;
serial:當(dāng)在可序列化的類上缺少 serialVersionUID 定義時(shí)的警告;
finally:任何 finally 子句不能正常完成時(shí)的警告;
all:關(guān)于以上所有情況的警告。

</code></pre>

4.定義注解

4.1 注解的定義

<pre> <code>
public @interface CustomAnnotationClass
</code></pre>

其中** @interface**說明這是一個(gè)自定義注解的定義.

4.2 定制化

定制化時(shí),有很多其它屬性可以用在自定義注解上,但是 ==目標(biāo)(Target==)和 ==保留策略(Retention Policy==)是最重要的兩個(gè)。

4.2.1 @Target

用來約束注解可以應(yīng)用的地方(如方法、類或字段),其中ElementType是枚舉類型

<pre>
<code>
public enum ElementType {
/*標(biāo)明該注解可以用于類、接口(包括注解類型)或enum聲明/
TYPE,

/** 標(biāo)明該注解可以用于字段(域)聲明,包括enum實(shí)例 */
FIELD,

/** 標(biāo)明該注解可以用于方法聲明 */
METHOD,

/** 標(biāo)明該注解可以用于參數(shù)聲明 */
PARAMETER,

/** 標(biāo)明注解可以用于構(gòu)造函數(shù)聲明 */
CONSTRUCTOR,

/** 標(biāo)明注解可以用于局部變量聲明 */
LOCAL_VARIABLE,

/** 標(biāo)明注解可以用于注解聲明(應(yīng)用于另一個(gè)注解上)*/
ANNOTATION_TYPE,

/** 標(biāo)明注解可以用于包聲明 */
PACKAGE,

/**
 * 標(biāo)明注解可以用于類型參數(shù)聲明(1.8新加入)
 * @since 1.8
 */
TYPE_PARAMETER,

/**
 * 類型使用聲明(1.8新加入)
 * @since 1.8
 */
TYPE_USE

}
</code>
</pre>

  • 當(dāng)注解未指定Target值時(shí),則此注解可以用于任何元素之上
  • 設(shè)定一個(gè)值:@Target(ElementType.METHOD)
  • 設(shè)定多個(gè)值時(shí)使用{}包含并用逗號(hào)隔開

<code>@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})</code>

4.2.2 @Retention

用來約束注解的生命周期,分別有三個(gè)值,源碼級(jí)別(source),類文件級(jí)別(class)或者運(yùn)行時(shí)級(jí)別(runtime)

  • SOURCE:注解將被編譯器丟棄(該類型的注解信息只會(huì)保留在源碼里,源碼經(jīng)過編譯后,注解信息會(huì)被丟棄,不會(huì)保留在編譯好的class文件里)

  • CLASS:注解在class文件中可用,但會(huì)被VM丟棄(該類型的注解信息會(huì)保留在源碼里和class文件里,在執(zhí)行的時(shí)候,不會(huì)加載到虛擬機(jī)中),請(qǐng)注意,當(dāng)注解未定義Retention值時(shí),默認(rèn)值是CLASS,如Java內(nèi)置注解,@Override、@Deprecated、@SuppressWarnning等

  • RUNTIME:注解信息將在運(yùn)行期(JVM)也保留,因此可以通過反射機(jī)制讀取注解的信息(源碼、class文件和執(zhí)行的時(shí)候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。

4.2.3 注解中的細(xì)節(jié)

<pre>
<code>
@Target(ElementType.TYPE) // 注解在類上
@Retention(RetentionPolicy.RUNTIME) //保留在運(yùn)行時(shí)
@interface CustmAnnotationClass {
/**
* Java 元注解
* 1. 目標(biāo)
* 2. 保留策略
*/
String info() default "Annotation";

}

@CustmAnnotationClass(info="OOP")
public class Test {

}
</code>
</pre>

  1. 注解支持以下類型:
  • 所有基本類型
    (int,float,boolean,byte,double,char,long,short)
  • String
  • Class
  • enum
  • Annomation
  • 上述類型的數(shù)組形式
  1. 注解可以作為元素的類型,也就是嵌套注解
  2. 注解默認(rèn)值限制

元素必須要么具有默認(rèn)值,要么在使用注解時(shí)提供元素的值。

對(duì)于非基本類型的元素,無論是在源代碼中聲明,還是在注解接口中定義默認(rèn)值,都不能以null作為值.當(dāng)然我們可以定義一些特殊的值,例如空字符串或負(fù)數(shù),表示某個(gè)元素不存在

4.2.4 注解中的繼承
  • 注解不能使用關(guān)鍵字extends來繼承某個(gè)@interface,但注解在編譯后,編譯器會(huì)自動(dòng)繼承java.lang.annotation.Annotation接口
  • @Inherited

使用了保留注解@Inherited,但這并不是真的繼承,只是通過使用@Inherited,可以讓子類Class對(duì)象使用getAnnotations()獲取父類被@Inherited修飾的注解,換句話說:這個(gè)類將自動(dòng)地把這個(gè)注解傳遞到所有子類中而不用在子類中聲明,通常,一個(gè)類繼承了父類,并不繼承父類的注解。這完全和使用注解的目的一致的:提供關(guān)于被注解的代碼的信息而不修改它們的行為。

所以:@Inheriated注解僅在存在繼承關(guān)系的類上產(chǎn)生效果,在接口和實(shí)現(xiàn)類上并不工作。
在默認(rèn)的情況下,父類的注解并不會(huì)被子類繼承。如果要繼承,就必須加上Inherited注解。

可以點(diǎn)擊這里看看哦

4.2.5 其他注解屬性介紹
  • @Documented 被修飾的注解會(huì)生成到j(luò)avadoc中

5.注解的獲取(反射)

  • 在使用反射之前必須使用import java.lang.reflect.* 來導(dǎo)入和反射相關(guān)的類。

  • 如果要得到某一個(gè)類或接口的注解信息,可以使用如下代碼:

<pre>
<code>
Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);
</code>
</pre>

  • 如果要得到全部的注解信息可使用如下語(yǔ)句:

<pre>
<code>
Annotation[] annotations = TestAnnotation.class.getAnnotations();

Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();

</code>
</pre>

getDeclaredAnnotations與getAnnotations類似,但它們不同的是getDeclaredAnnotations得到的是當(dāng)前成員所有的注解,不包括繼承的。而getAnnotations得到的是包括繼承的所有注解。

  • 如果要得到其它成員的注解,可先得到這個(gè)成員,然后再得到相應(yīng)的注解。如得到myMethod的注解。

<pre>
<code>
Method method = TestAnnotation.class.getMethod("myMethod", null);

Annotation annotation = method.getAnnotation(MyAnnotation.class);
</code>
</pre>
注:要想使用反射得到注解信息,這個(gè)注解必須使用

@Retention(RetentionPolicy.RUNTIME)進(jìn)行注解。

  • 判斷指定類型的注解是否存在于此元素

<pre>
<code>
isAnnotationPresent(Class<? extends Annotation> annotationClass)
</code>
</pre>

6. Java8 變化

  • @Repeatable
    表示在同一個(gè)位置重復(fù)相同的注解
    <code>@Repeatable(MyAnnotation.class)</code>
  • 新增ElementType

TYPE_PARAMETER 和 TYPE_USE ,在Java8前注解只能標(biāo)注在一個(gè)聲明(如字段、類、方法)上,Java8后,新增的TYPE_PARAMETER可以用于標(biāo)注類型參數(shù),而TYPE_USE則可以用于標(biāo)注任意類型(不包括class)。

7.自動(dòng)測(cè)試機(jī)的寫法

7.1自動(dòng)測(cè)試機(jī)的原理:

使用Annotation來Annotate元素的實(shí)質(zhì)是:每一個(gè)ElementType內(nèi)部的元素都有兩個(gè)方法,分別為
(注:為方便理解,以下使用的TestCase為某個(gè)特定的自定義注釋)

(1)isAnnotationPresent(TestCase.class) //判斷該元素是否被TestCase所注釋

(2)getAnnotation(TestCase.class) //獲得TestCase的類對(duì)象

7.2自動(dòng)測(cè)試機(jī)的工作過程是:

(1)首先通過反射,獲得被測(cè)類o中的每一個(gè)方法

(2)對(duì)每一個(gè)方法通過使用isAnnotationPresent(TestCase.class)判斷其是否被TestCase所注釋(注意是.class?。?/p>

(3)如果某方法method被TestCase所注釋,則通過method的getAnnotation(TestCase.class)獲得TestCase的類對(duì)象tc

(4)通過tc的value()方法,獲得該類對(duì)象的屬性value

(注:此處使用的value()方法,正是在TestCase中定義的value屬性,再次理解在注釋中定義的value既是屬性,也是方法)

(5)調(diào)用method方法的invoke(o,value),用value對(duì)method進(jìn)行測(cè)試

參考福利

官方Java注解地址:http://docs.oracle.com/javase/tutorial/java/annotations/

維基百科中關(guān)于Java注解的解釋:http://en.wikipedia.org/wiki/Java_annotation

Java規(guī)范請(qǐng)求250:http://en.wikipedia.org/wiki/JSR_250

Oracle 注解白皮書:http://www.oracle.com/technetwork/articles/hunter-meta-096020.html

注解API:http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html

最后編輯于
?著作權(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)容