詳解Java注解( Annotation )
注解的定義:
注解(Annotation),也叫元數(shù)據(jù)。一種代碼級(jí)別的說明。它是JDK1.5及以后版本引入的一個(gè)特性,與類、接口、枚舉是在同一個(gè)層次。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對(duì)這些元素進(jìn)行說明,注釋
注解的作用
生成文檔
代碼分析,通過代碼里的元數(shù)據(jù)來對(duì)代碼進(jìn)行分析
在編譯的時(shí)候進(jìn)行檢查
JDK自帶的注解
在開發(fā)過程中,我們見到的JDK自帶的注解主要有三個(gè),分別是@Override
,@SuppressWarnings
,@Deprecated
,作用分別如下:
@Override
:主要用于標(biāo)識(shí)所用的方法是繼承自父類的方法,從而在編譯的過程中可以被編譯器檢測(cè)到,如果某個(gè)方法使用了該注解,但是方法的簽名(方法名以及參數(shù)類型)與父類不一致,則在編譯的過程中,編譯器會(huì)拋出錯(cuò)誤,用于提示開發(fā)者。
最常見的就是
toString()
方法了,該方法繼承自O(shè)bject類。如果我們?cè)谥貙懺摲椒ǖ臅r(shí)候,沒有使用該注解,然后不小心將該方法的名字寫錯(cuò)如下所示:
package cn.xuhuanfeng.annotation;
public class TestAnnotation {
public static void main(String[] args) {
TestAnnotation test = new TestAnnotation();
System.out.println(test.toString());
}
public String tostring() {
return "Not true";
}
}
輸出結(jié)果為:cn.xuhuanfeng.annotation.TestAnnotation@15db9742
,顯然我們可以看到,toString()方法輸出的結(jié)果顯然不是我們所期待的,有時(shí)候就會(huì)很莫名其妙了(原因是重寫toString()
方法的時(shí)候,不小心將S寫錯(cuò)成了s,編譯器會(huì)理解成有一個(gè)新的方法,叫tostring()
,這是正確的,所以就導(dǎo)致了調(diào)用的時(shí)候出現(xiàn)了預(yù)期之外的結(jié)果了),但是如果我們?cè)谥貙?code>toString()方法的時(shí)候,加上@Override
,這個(gè)時(shí)候,如果還是按照上面的寫法,編譯器就會(huì)告訴我們The method tostring() of type TestAnnotation must override or implement a supertype method
,于是,我們很容易就能發(fā)現(xiàn)問題所在了,這是注解的好處之一,也是@Override
的作用,具體可以查看其源碼即可。
@Deprecated
:主要用于標(biāo)識(shí)該包、方法、域、變量等已經(jīng)不推薦使用了,一旦標(biāo)識(shí)了該注解,則對(duì)應(yīng)的方法、域等會(huì)劃上刪除線如下所示
@Deprecated
public void test(){
System.out.println("Deprecated");
}
@SuppressWarnings
:主要用于壓制編譯器發(fā)出的警告,該注解需要提供參數(shù),包括了
unchecked
all
等,分別對(duì)應(yīng)不同的壓制范圍,如:
@SuppressWarnings("all")
public void test01(){
}
自定義注解
上面我們看到了JDK中自帶的注解,雖然很有用,但是畢竟范圍有限,種類也有限,實(shí)用性不是很大,于是Java開發(fā)者為我們提供了自定義的注解,極大了擴(kuò)展了該功能,下面我們就詳細(xì)來看下自定義注解的內(nèi)容。
元注解
為了使用自定義注解,首先我們需要了解一個(gè)概念:元注解,所謂的元注解,其實(shí)就是注解的注解,也就是用來表示注解的注解,JDK中包含的元注解中比較常用的有以下幾種類型: @Target
, @Retention
, @Documented
, @Inherited
,其中前面兩種在實(shí)際開發(fā)過程中用得比較多,所以下面我們著重來介紹這兩種:
@Target
:用于表示所標(biāo)識(shí)的注解的使用范圍,其值可以是
ElementType.PACKAGE
,ElementType.CONSTRUCTOR
,ElementType.METHOD
,ElementType.FIELD
等,分別對(duì)應(yīng)的標(biāo)識(shí)對(duì)象為 包,構(gòu)造器,方法,域變量,也就是說,只有包含了該范圍,我們定義出來的注解才能用于對(duì)應(yīng)的域,多種類型可以組合使用,只需要使用{}
包括起即可。具體使用如下:
@Target({ElementType.PACKAGE,ElementType.CONSTRUCTOR ,ElementType.METHOD, ElementType.FIELD})
@Retention
:用于標(biāo)識(shí)注解的存活周期,包括了
RetentionPolicy.RUNTIME
,RetentionPolicy.CLASS
,RetentionPolicy.SOURCE
,分別對(duì)應(yīng)存活周期為運(yùn)行時(shí),字節(jié)碼,源文件。運(yùn)行時(shí):標(biāo)識(shí)該注解存在于字節(jié)碼中,并且在運(yùn)行過程中會(huì)被JVM加載,可用于反射操作。
字節(jié)碼:標(biāo)識(shí)該注解存在于字節(jié)碼中,但是運(yùn)行時(shí)不被JVM加載,默認(rèn)的形式。
源文件:標(biāo)識(shí)該注解只存在源文件中,在編譯過程會(huì)被編譯器丟棄。
具體使用如下:
@Retention(RetentionPolicy.RUNTIME)
自定義注解
學(xué)習(xí)完了元注解之后,我們就可以開始手動(dòng)編寫自定義的注解了。
- 格式:
自定義注解的書寫方式跟普通的Java類的書寫方式接近,只是將class
關(guān)鍵字替換為@interface
,如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PACKAGE})
public @interface MyAnnotation {
}
從上面的元注解部分我們可以知道,我們定義的注解MyAnnotation
只能用于注解包,而不能用于注解方法、域等。
- 參數(shù):
從前面的@SuppressWarnings
中我們可以知道,注解還可以帶參數(shù),不過在注解中的參數(shù)類型有點(diǎn)奇怪,如下:
String value();// String為參數(shù)類型 value() 整體為變量
String[] value(); // String[] 為參數(shù)類型 value() 整體為變量
默認(rèn)情況下,如果只有一個(gè)參數(shù)類型,我們將變量命名為value(),我們也可以聲明多個(gè)參數(shù)
String name();
int age(); // 其他類型依此類推
在注解中的所有參數(shù)均可以指定默認(rèn)的值,如下:
String name() default "";
int age() default -1;
由于在使用注解中我們無法標(biāo)識(shí)錯(cuò)誤的情況,所以一般情況下,會(huì)將默認(rèn)類型指定為一個(gè)不合理值,用來處理注解時(shí)判斷所使用的值是合理還是不合理。
- 使用:
定義完了一個(gè)我們的自定義注解之后,接下來我們來看下如何使用它。使用的方式跟JDK自帶的注解的方式基本一致,指定對(duì)應(yīng)的鍵值對(duì),key為定義的參數(shù)名字,值為需要傳入的值,如果是數(shù)組類型,則傳入數(shù)組即可。
@MyAnnotation(name="xuhaunfeng",age=23)
public void test(){}
//在MyAnnotation中多增加一個(gè)變量為 String[] parents();
@MyAnnotation(name="xuhaunfeng",age=23,parents={"AA","BB"})
public void test(){}
注解的應(yīng)用
看完了上面的內(nèi)容,可能你會(huì)覺得如果注解只是上面的用法,感覺上是沒有任何作用的,確實(shí),上面所介紹的內(nèi)容都是注解的格式、定義等,但是沒有涉及到其應(yīng)用,注解配合反射,可以實(shí)現(xiàn)很多功能,例如:ORM的實(shí)現(xiàn),框架中Annotation的應(yīng)用等,不過目前我還沒有學(xué)習(xí)到這些內(nèi)容,所以在后期學(xué)習(xí)之后將會(huì)補(bǔ)上,敬請(qǐng)期待。
參考說明
這篇文章只是我個(gè)人學(xué)習(xí)過程中的一些筆記,不帶有任何的商業(yè)目的,在學(xué)習(xí)過程中參考了很多的資料,主要參考深入理解Java:注解(Annotation)自定義注解入門 By竹子,在此對(duì)竹子表示感謝。如果本文涉及的一些內(nèi)容有一些版權(quán)爭(zhēng)議,還請(qǐng)與我聯(lián)系。