關(guān)于Java注解學(xué)習(xí)總結(jié)

什么是注解

注解是 Java 5 的一個新特性。注解是插入你代碼中的一種注釋或者說是一種元數(shù)據(jù)(meta data)。這些注解信息可以在編譯期使用預(yù)編譯工具進(jìn)行處理(pre-compiler tools)佳吞,也可以在運(yùn)行期使用 Java 反射機(jī)制進(jìn)行處理。

那么通俗來說俯逾,注解就是我們所說的標(biāo)簽昆淡,我們可以把一些類,方法盒件,變量蹬碧,參數(shù)添加注解,即加上標(biāo)簽來表明這些是干啥的炒刁,以便有需要的時候查看恩沽。

注解的聲明

使用@interface聲明:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)     

public @interface Test {
}
  • 使用@Target注解傳入ElementType.METHOD參數(shù)來標(biāo)明@Test只能用于方法上。

  • 使用@Retention(RetentionPolicy.TRUNTIME)來表示該注解生存期是運(yùn)行時翔始。

  • @Target@Retention是由Java提供的元注解罗心,即可以標(biāo)記自定義注解的注解。

元注解

@Target

@Target用來約束注解可以應(yīng)用的地方(如類绽昏、方法协屡、方法參數(shù)、字段)全谤,ElementType是枚舉類型肤晓,其定義如下:

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)用于另一個注解上)*/
ANNOTATION_TYPE,

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

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

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

當(dāng)注解未指定Target值時补憾,則此注解可以用于任何元素上,多個值使用{}包含并用逗號隔開卷员,如下:

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

@Retention

@Retention用來約束注解的生命周期盈匾,有三個級別:源碼級別(SOURCE)、類文件級別(CLASS)毕骡、運(yùn)行時級別(RUNTIME),

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

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

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

@Inherited

@Inherited 可以讓注解被繼承瞬矩,但這并不是真的繼承,只是通過使用@Inherited锋玲,可以讓子類Class對象使用getAnnotations()獲取父類被@Inherited修飾的注解景用。

/** 使用@Inherited注解會被子類所繼承 */
@Retention(Retention.RUNTIME)
@Inherited
public @interface InheritedTest {
    String value();
}

/** 未聲明@Inherited, 不會被子類繼承*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NoInheritedTest {
    String value();
}

/**父類*/

@InheritedTest("InheritedTest:使用@Inherited的class")
@NoInheritedTest("NoInheritedTest:未使用@Inherited的class")
public class Parent {

@InheritedTest("InheritedTest:使用@Inherited method")
@NoInheritedTest("NoInheritedTest:未使用@Inherited method")
public void method(){
    
}
@InheritedTest("InheritedTest:使用@Inherited method2")
@NoInheritedTest("NoInheritedTest:未使用@Inherited method2")
public void method2(){
    
}

@InheritedTest("InheritedTest:使用@Inherited field")
@NoInheritedTest("NoInheritedTest:未使用@Inherited field")
public String a;
}   

/**子類  只繼承了一個method方法 */
public class Child extends Parent {

@Override
public void method() {
    }
}


/**使用反射進(jìn)行測試 */
public class Test {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
    Class<Child> childClass = Child.class;
    //對類測試
    System.out.println("-------------------------------------");
    System.out.println("對類測試");
    if (childClass.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(childClass.getAnnotation(InheritedTest.class).value());
    }

    if (childClass.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(childClass.getAnnotation(NoInheritedTest.class).value());
    }

    //對方法1測試
    System.out.println("-------------------------------------");
    System.out.println("對方法1測試");
    Method method = childClass.getMethod("method", null);
    if (method.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(method.getAnnotation(InheritedTest.class).value());
    }

    if (method.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(method.getAnnotation(NoInheritedTest.class).value());
    }

    //對方法2測試
    System.out.println("-------------------------------------");
    System.out.println("對方法2測試");
    Method method2 = childClass.getMethod("method2");
    if (method2.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(method2.getAnnotation(InheritedTest.class).value());
    }

    if (method2.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(method2.getAnnotation(NoInheritedTest.class).value());
    }

    //對變量測試
    System.out.println("-------------------------------------");
    System.out.println("對變量測試");
    Field field = childClass.getField("a");
    if (field.isAnnotationPresent(InheritedTest.class)) {
        System.out.println(field.getAnnotation(InheritedTest.class).value());
    }

    if (field.isAnnotationPresent(NoInheritedTest.class)) {
        System.out.println(field.getAnnotation(NoInheritedTest.class).value());
    }
}
}

/**輸出結(jié)果*/
-------------------------------------
對類測試
InheritedTest:使用@Inherited的class
-------------------------------------
對方法1測試
-------------------------------------
對方法2測試
InheritedTest:使用@Inherited method2
NoInheritedTest:未使用@Inherited method2
-------------------------------------
對變量測試
InheritedTest:使用@Inherited field
NoInheritedTest:未使用@Inherited field


我們可以得出結(jié)論惭蹂,使用`@Inherited`注解類的時候伞插,子類繼承了父類的注解,但是第一個方法沒有繼承到注解盾碗,說明`@Inherited`對方法無效媚污,但方法2和域拿到的是父類的注解,所以有輸出廷雅。

@Repeatable

在Java SE 8中引入的 @Repeatable 注解表明標(biāo)記的注解可以多次應(yīng)用于相同的聲明或類型使用耗美。
可以這么理解:有個人可以音樂家,畫家航缀,程序員商架,那我們就用@Repeatable給這個人貼上這三個標(biāo)簽。

@Retention(RetentionPolicy.RUNTIME)
public @interface Persons {
    Person[] value();   
}

@Repeatable(Persons.class)
public @interface Person {
    String role default "";
}

@Person(role="Painter")
@Person(role="Musician")
@Person(role="Lion")
public class KUN {}

注解的成員變量及其數(shù)據(jù)類型

我們定義注解芥玉,也可以定義一些成員變量蛇摸,而且還可以用default指定默認(rèn)值。

@Retention(RetentionPolicy.RUNTIME)
public @interface FavouriteAnnotation {

int num() default 0;

String name() default "X JAPAN";

}

/** 默認(rèn)第0位最喜愛的是X JAPAN*/
@FavouriteAnnotation()
public class KUN {}

/** 指定第1位最喜愛的是Queen*/
@FavouriteAnnotation(num=1, name="Queen")
public class KUN {}

注解支持的數(shù)據(jù)類型有:

  • 所有基本類型(int,float,boolean,byte,double,char,long,short)

  • String

  • Class

  • enum

  • Annotation

  • 上述類型的數(shù)組

注解與反射

注解通過反射獲取灿巧,使用Class對象的isAnnotationPresent()方法判斷是否應(yīng)用了某個注解,如果指定類型的注解存在于此元素上赶袄,則返回 true,否則返回 false抠藕。
public boolean isAnnotationPresent(Class<? extend Annotation> annotationClass)

使用getAnnotation()方法獲取Annotation對象饿肺。
public <A extebds Annotation> A getAnnotation(Class<A> annotationClass) {}

使用getAnnotations() 獲取此元素上存在的所有注解,包括從父類繼承的幢痘。
public Annotation[] getAnnotations() {}

使用getDeclaredAnnotations(),返回直接存在于此元素上的所有注解唬格,注意家破,不包括父類的注解颜说,調(diào)用者可以隨意修改返回的數(shù)組购岗;這不會對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響,沒有則返回長度為0的數(shù)組

public native Annotation[] getDeclaredAnnotations()

注解的應(yīng)用場景

注解是一系列元數(shù)據(jù)门粪,它提供數(shù)據(jù)用來解釋程序代碼喊积,但是注解并非是所解釋的代碼本身的一部分。注解對于代碼的運(yùn)行效果沒有直接影響玄妈。
注解有許多用處乾吻,主要如下:

  • 提供信息給編譯器: 編譯器可以利用注解來探測錯誤和警告信息
  • 編譯階段時的處理: 軟件工具可以用來利用注解信息來生成代碼、Html文檔
    或者做其它相應(yīng)處理拟蜻。
  • 運(yùn)行時的處理: 某些注解可以在程序運(yùn)行的時候接受代碼的提取
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绎签,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酝锅,更是在濱河造成了極大的恐慌诡必,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搔扁,死亡現(xiàn)場離奇詭異爸舒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)稿蹲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門扭勉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苛聘,你說我怎么就攤上這事涂炎。” “怎么了设哗?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵璧尸,是天一觀的道長。 經(jīng)常有香客問我熬拒,道長爷光,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任澎粟,我火速辦了婚禮蛀序,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘活烙。我一直安慰自己徐裸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布啸盏。 她就那樣靜靜地躺著重贺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上气笙,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天次企,我揣著相機(jī)與錄音,去河邊找鬼潜圃。 笑死缸棵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谭期。 我是一名探鬼主播堵第,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隧出!你這毒婦竟也來了踏志?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胀瞪,失蹤者是張志新(化名)和其女友劉穎狰贯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赏廓,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涵紊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了幔摸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摸柄。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖既忆,靈堂內(nèi)的尸體忽然破棺而出驱负,到底是詐尸還是另有隱情,我是刑警寧澤患雇,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布跃脊,位于F島的核電站,受9級特大地震影響苛吱,放射性物質(zhì)發(fā)生泄漏酪术。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一翠储、第九天 我趴在偏房一處隱蔽的房頂上張望绘雁。 院中可真熱鬧,春花似錦援所、人聲如沸庐舟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挪略。三九已至历帚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杠娱,已是汗流浹背挽牢。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墨辛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓趴俘,卻偏偏與公主長得像睹簇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寥闪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355