1
2
3
4
5
6
7
8
9
10
|
package com.anno; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention (RetentionPolicy.RUNTIME) public @interface MyAnno { //當(dāng)注解中使用的屬性名為value時(shí),對其賦值時(shí)可以不指定屬性的名稱而直接寫上屬性值接口; //除了value意外的變量名都需要使用name=value的方式賦值。 String value() default "ddd" ; //取的注解中的值 @MyAnno(value ="sss")默認(rèn)值 String name() default "silence" ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package anno; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; @MyAnnotation ( "sss" ) public class AnnotationTest { public void COUT(){ System.out.println( "COUT" ); } public static void main(String[] args) throws Exception{ //1、讀取注解 Annotation[] annotations = AnnotationTest. class .getAnnotations(); System.out.println(((MyAnnotation)annotations[ 0 ]).value()); System.out.println(((MyAnnotation)annotations[ 0 ]).name()); //2、判斷使用注解的元素 Class c = AnnotationTest. class ; c.isAnnotationPresent(MyAnnotation. class ); System.out.println(c.isAnnotationPresent(MyAnnotation. class )); //3、元素注解 AnnotatedElement element = MyAnnotation. class ; element.getAnnotation(MyAnnotation. class ); } } |
打印:sss
一、java內(nèi)置注解
1、@Target 表示該注解用于什么地方,可能的 ElemenetType 參數(shù)包括:
ElemenetType.CONSTRUCTOR
構(gòu)造器聲明
ElemenetType.FIELD
域聲明(包括 enum 實(shí)例)
ElemenetType.LOCAL_VARIABLE
局部變量聲明
ElemenetType.METHOD
方法聲明
ElemenetType.PACKAGE
包聲明
ElemenetType.PARAMETER
參數(shù)聲明
ElemenetType.TYPE
類,接口(包括注解類型)或enum聲明
2、@Retention 表示在什么級(jí)別保存該注解信息??蛇x的 RetentionPolicy 參數(shù)包括:
RetentionPolicy.SOURCE
注解將被編譯器丟棄
RetentionPolicy.CLASS
注解在class文件中可用,但會(huì)被VM丟棄
RetentionPolicy.RUNTIME VM
將在運(yùn)行期也保留注釋,因此可以通過反射機(jī)制讀取注解的信息。
3、@Documented
將此注解包含在 javadoc 中
4、@Inherited
允許子類繼承父類中的注解'
5、@Deprecated
表示當(dāng)前元素是不贊成使用的。
6、@Override
表示當(dāng)前方法是覆蓋父類的方法。
7、@SuppressWarnings
表示關(guān)閉一些不當(dāng)?shù)木幾g器警告信息。
ava注解是附加在代碼中的一些元信息,用于一些工具在編譯、運(yùn)行時(shí)進(jìn)行解析和使用,起到說明、配置的功能。注解不會(huì)也不能影響代碼的實(shí)際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。
1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四種。
1.1、@Retention: 定義注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解僅存在于源碼中,在class字節(jié)碼文件中不包含
@Retention(RetentionPolicy.CLASS) // 默認(rèn)的保留策略,注解會(huì)在class字節(jié)碼文件中存在,但運(yùn)行時(shí)無法獲得,
@Retention(RetentionPolicy.RUNTIME) // 注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過反射獲取到
1.2、@Target:定義注解的作用目標(biāo)
其定義的源碼為:
1
2
3
4
5
6
|
@Documented @Retention (RetentionPolicy.RUNTIME) @Target (ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); } |
@Target(ElementType.TYPE)
//接口、類、枚舉、注解
@Target(ElementType.FIELD)
// 字段、枚舉的常量
@Target(ElementType.METHOD)
// 方法
@Target(ElementType.PARAMETER)
// 方法參數(shù)
@Target(ElementType.CONSTRUCTOR)
// 構(gòu)造函數(shù)
@Target(ElementType.LOCAL_VARIABLE)
// 局部變量
@Target(ElementType.ANNOTATION_TYPE)
// 注解
@Target(ElementType.PACKAGE)
/ // 包 由以上的源碼可以知道,他的elementType 可以有多個(gè),一個(gè)注解可以為類的,方法的,字段的等等
1.3、@Document:說明該注解將被包含在javadoc中
1.4、@Inherited:說明子類可以繼承父類中的該注解
2、java 注解的自定義 下面是自定義注解的一個(gè)例子
1
2
3
4
5
6
7
|
@Documented @Target ({ElementType.TYPE,ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface Yts { public enum YtsType{util,entity,service,model}; public YtsType classType() default YtsType.util; } |
1
2
3
4
5
6
7
|
@Documented @Retention (RetentionPolicy.RUNTIME) @Target (ElementType.METHOD) @Inherited public @interface HelloWorld { public String name() default "" ; } |
@Retention(RetentionPolicy.RUNTIME)
定義的這個(gè)注解是注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過反射獲取到。
@Target({ElementType.TYPE,ElementType.METHOD})
因此這個(gè)注解可以是類注解,也可以是方法的注解
這樣一個(gè)注解就自定義好了,當(dāng)然注解里面的成員可以為基本的數(shù)據(jù)類型,也可以為數(shù)據(jù),Object等等
3 .注解是定義好了,那么怎么來得到,解析注解呢?
java的反射機(jī)制可以幫助,得到注解,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public class ParseAnnotation { public void parseMethod(Class clazz) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException{ Object obj = clazz.getConstructor( new Class[]{}).newInstance( new Object[]{}); for (Method method : clazz.getDeclaredMethods()){ HelloWorld say = method.getAnnotation(HelloWorld. class ); String name = "" ; if (say != null ){ name = say.name(); method.invoke(obj, name); } Yts yts = (Yts)method.getAnnotation(Yts. class ); if (yts != null ){ if (YtsType.util.equals(yts.classType())){ System.out.println( "this is a util method" ); } else { System.out.println( "this is a other method" ); } } } } @SuppressWarnings ( "unchecked" ) public void parseType(Class clazz) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{ Yts yts = (Yts) clazz.getAnnotation(Yts. class ); if (yts != null ){ if (YtsType.util.equals(yts.classType())){ System.out.println( "this is a util class" ); } else { System.out.println( "this is a other class" ); } } } } |
前一個(gè)方法是解析得到方法注解的,后一個(gè)方法是得到類注解的
以下是測試方法類
1
2
3
4
5
6
7
8
9
10
11
12
|
@Yts (classType =YtsType.util) public class SayHell { @HelloWorld (name = " 小明 " ) @Yts public void sayHello(String name){ if (name == null || name.equals( "" )){ System.out.println( "hello world!" ); } else { System.out.println(name + "say hello world!" ); } } } |
1
2
3
4
5
|
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException { ParseAnnotation parse = new ParseAnnotation(); parse.parseMethod(SayHell. class ); parse.parseType(SayHell. class ); } |
1、Annotation的工作原理:
JDK5.0中提供了注解的功能,允許開發(fā)者定義和使用自己的注解類型。該功能由一個(gè)定義注解類型的語法和描述一個(gè)注解聲明的語法,讀取注解的API,一個(gè)使用注解修飾的class文件和一個(gè)注解處理工具組成。
Annotation并不直接影響代碼的語義,但是他可以被看做是程序的工具或者類庫。它會(huì)反過來對正在運(yùn)行的程序語義有所影響。
Annotation可以沖源文件、class文件或者在運(yùn)行時(shí)通過反射機(jī)制多種方式被讀取。
2、@Override注解:
java.lang
注釋類型 Override
@Target(value=METHOD)
@Retention(value=SOURCE)
public@interface Override
表示一個(gè)方法聲明打算重寫超類中的另一個(gè)方法聲明。如果方法利用此注釋類型進(jìn)行注解但沒有重寫超類方法,則編譯器會(huì)生成一條錯(cuò)誤消息。
@Override注解表示子類要重寫父類的對應(yīng)方法。
Override是一個(gè)Marker annotation,用于標(biāo)識(shí)的Annotation,Annotation名稱本身表示了要給工具程序的信息。
下面是一個(gè)使用@Override注解的例子:
1
2
3
4
5
6
7
8
9
10
|
class A { private String id; A(String id){ this .id = id; } @Override public String toString() { return id; } } |
3、@Deprecated注解:
java.lang
注釋類型 Deprecated
@Documented
@Retention(value=RUNTIME)
public @interface Deprecated
用 @Deprecated 注釋的程序元素,不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執(zhí)行重寫時(shí),編譯器會(huì)發(fā)出警告。
@Deprecated注解表示方法是不被建議使用的。
Deprecated是一個(gè)Marker annotation。
下面是一個(gè)使用@Deprecated注解的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class A { private String id; A(String id){ this .id = id; } @Deprecated public void execute(){ System.out.println(id); } public static void main(String[] args) { A a = new A( "a123" ); a.execute(); } } |
4、@SuppressWarnings注解:
java.lang 注釋類型 SuppressWarnings @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings
指示應(yīng)該在注釋元素(以及包含在該注釋元素中的所有程序元素)中取消顯示指定的編譯器警告。注意,在給定元素中取消顯示的警告集是所有包含元素中取消顯示的警告的超集。例如,如果注釋一個(gè)類來取消顯示某個(gè)警告,同時(shí)注釋一個(gè)方法來取消顯示另一個(gè)警告,那么將在此方法中同時(shí)取消顯示這兩個(gè)警告。
根據(jù)風(fēng)格不同,程序員應(yīng)該始終在最里層的嵌套元素上使用此注釋,在那里使用才有效。如果要在特定的方法中取消顯示某個(gè)警告,則應(yīng)該注釋該方法而不是注釋它的類。
@SuppressWarnings注解表示抑制警告。
下面是一個(gè)使用@SuppressWarnings注解的例子:
1
2
3
4
5
|
@SuppressWarnings ( "unchecked" ) public static void main(String[] args) { List list = new ArrayList(); list.add( "abc" ); } |
5、自定義注解:
使用@interface自定義注解時(shí),自動(dòng)繼承了java.lang.annotation.Annotation接口,由編譯程序自動(dòng)完成其他細(xì)節(jié)。在定義注解時(shí),不能繼承其他的注解或接口。
自定義最簡單的注解:
1
2
|
public @interface MyAnnotation { } |
使用自定義注解:
1
2
3
4
5
6
|
public class AnnotationTest2 { @MyAnnotation public void execute(){ System.out.println( "method" ); } } |
5.1、添加變量:
1
2
3
|
public @interface MyAnnotation { String value1(); } |
使用自定義注解:
1
2
3
4
5
6
|
public class AnnotationTest2 { @MyAnnotation (value1= "abc" ) public void execute(){ System.out.println( "method" ); } } |
當(dāng)注解中使用的屬性名為value時(shí),對其賦值時(shí)可以不指定屬性的名稱而直接寫上屬性值接口;除了value意外的變量名都需要使用name=value的方式賦值。
5.2、添加默認(rèn)值:
1
2
3
|
public @interface MyAnnotation { String value1() default "abc" ; } |
5.3、多變量使用枚舉:
1
2
3
4
5
6
7
|
public @interface MyAnnotation { String value1() default "abc" ; MyEnum value2() default MyEnum.Sunny; } enum MyEnum{ Sunny,Rainy } |
使用自定義注解:
1
2
3
4
5
6
|
public class AnnotationTest2 { @MyAnnotation (value1= "a" , value2=MyEnum.Sunny) public void execute(){ System.out.println( "method" ); } } |
5.4、數(shù)組變量:
1
2
3
|
public @interface MyAnnotation { String[] value1() default "abc" ; } |
使用自定義注解:
1
2
3
4
5
6
|
public class AnnotationTest2 { @MyAnnotation (value1={ "a" , "b" }) public void execute(){ System.out.println( "method" ); } } |
6、設(shè)置注解的作用范圍:
@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Retention
指示注釋類型的注釋要保留多久。如果注釋類型聲明中不存在 Retention 注釋,則保留策略默認(rèn)為 RetentionPolicy.CLASS。
只有元注釋類型直接用于注釋時(shí),Target 元注釋才有效。如果元注釋類型用作另一種注釋類型的成員,則無效。
public enum RetentionPolicy
extends Enum<RetentionPolicy>
注釋保留策略。此枚舉類型的常量描述保留注釋的不同策略。它們與 Retention 元注釋類型一起使用,以指定保留多長的注釋。
CLASS
編譯器將把注釋記錄在類文件中,但在運(yùn)行時(shí) VM 不需要保留注釋。
RUNTIME
編譯器將把注釋記錄在類文件中,在運(yùn)行時(shí) VM 將保留注釋,因此可以反射性地讀取。
SOURCE
編譯器要丟棄的注釋。
@Retention注解可以在定義注解時(shí)為編譯程序提供注解的保留策略。
屬于CLASS保留策略的注解有@SuppressWarnings,該注解信息不會(huì)存儲(chǔ)于.class文件。
6.1、在自定義注解中的使用例子:
1
2
3
4
|
@Retention (RetentionPolicy.CLASS) public @interface MyAnnotation { String[] value1() default "abc" ; } |
7、使用反射讀取RUNTIME保留策略的Annotation信息的例子:
java.lang.reflect
接口AnnotatedElement
所有已知實(shí)現(xiàn)類:
AccessibleObject, Class, Constructor, Field, Method, Package
表示目前正在此 VM 中運(yùn)行的程序的一個(gè)已注釋元素。該接口允許反射性地讀取注釋。由此接口中的方法返回的所有注釋都是不可變并且可序列化的。調(diào)用者可以修改已賦值數(shù)組枚舉成員的訪問器返回的數(shù)組;這不會(huì)對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
如果此接口中的方法返回的注釋(直接或間接地)包含一個(gè)已賦值的 Class 成員,該成員引用了一個(gè)在此 VM 中不可訪問的類,則試圖通過在返回的注釋上調(diào)用相關(guān)的類返回的方法來讀取該類,將導(dǎo)致一個(gè) TypeNotPresentException。
isAnnotationPresent
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定類型的注釋存在于此元素上,則返回 true,否則返回 false。此方法主要是為了便于訪問標(biāo)記注釋而設(shè)計(jì)的。
參數(shù):
annotationClass - 對應(yīng)于注釋類型的 Class 對象
返回:
如果指定注釋類型的注釋存在于此對象上,則返回 true,否則返回 false
拋出:
NullPointerException - 如果給定的注釋類為 null
從以下版本開始:
1.5
getAnnotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。
參數(shù):
annotationClass - 對應(yīng)于注釋類型的 Class 對象
返回:
如果該元素的指定注釋類型的注釋存在于此對象上,則返回這些注釋,否則返回 null
拋出:
NullPointerException - 如果給定的注釋類為 null
從以下版本開始:
1.5
getAnnotations
Annotation[] getAnnotations()
返回此元素上存在的所有注釋。(如果此元素沒有注釋,則返回長度為零的數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
返回:
此元素上存在的所有注釋
從以下版本開始:
1.5
getDeclaredAnnotations
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注釋。與此接口中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在于此元素上,則返回長度為零的一個(gè)數(shù)組。)該方法的調(diào)用者可以隨意修改返回的數(shù)組;這不會(huì)對其他調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
返回:
直接存在于此元素上的所有注釋
從以下版本開始:
1.5
下面是使用反射讀取RUNTIME保留策略的Annotation信息的例子:
自定義注解:
1
2
3
4
|
@Retention (RetentionPolicy.RUNTIME) public @interface MyAnnotation { String[] value1() default "abc" ; } |
使用自定義注解:
1
2
3
4
5
6
7
|
public class AnnotationTest2 { @MyAnnotation (value1={ "a" , "b" }) @Deprecated public void execute(){ System.out.println( "method" ); } } |
讀取注解中的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { AnnotationTest2 annotationTest2 = new AnnotationTest2(); //獲取AnnotationTest2的Class實(shí)例 Class<AnnotationTest2> c = AnnotationTest2. class ; //獲取需要處理的方法Method實(shí)例 Method method = c.getMethod( "execute" , new Class[]{}); //判斷該方法是否包含MyAnnotation注解 if (method.isAnnotationPresent(MyAnnotation. class )){ //獲取該方法的MyAnnotation注解實(shí)例 MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation. class ); //執(zhí)行該方法 method.invoke(annotationTest2, new Object[]{}); //獲取myAnnotation String[] value1 = myAnnotation.value1(); System.out.println(value1[ 0 ]); } //獲取方法上的所有注解 Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations){ System.out.println(annotation); } } |
8、限定注解的使用:
限定注解使用@Target。
@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Target
指示注釋類型所適用的程序元素的種類。如果注釋類型聲明中不存在 Target 元注釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元注釋,則編譯器強(qiáng)制實(shí)施指定的使用限制。 例如,此元注釋指示該聲明類型是其自身,即元注釋類型。它只能用在注釋類型聲明上:
1
2
3
4
|
@Target (ElementType.ANNOTATION_TYPE) public @interface MetaAnnotationType { ... } |
此元注釋指示該聲明類型只可作為復(fù)雜注釋類型聲明中的成員類型使用。它不能直接用于注釋:
1
2
3
4
|
@Target ({}) public @interface MemberType { ... } |
這是一個(gè)編譯時(shí)錯(cuò)誤,它表明一個(gè) ElementType 常量在 Target 注釋中出現(xiàn)了不只一次。例如,以下元注釋是非法的:
1
2
3
4
|
@Target ({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD}) public @interface Bogus { ... } |
1
2
|
public enum ElementType extends Enum<ElementType> |
程序元素類型。此枚舉類型的常量提供了 Java 程序中聲明的元素的簡單分類。
這些常量與 Target 元注釋類型一起使用,以指定在什么情況下使用注釋類型是合法的。
ANNOTATION_TYPE 注釋類型聲明 CONSTRUCTOR 構(gòu)造方法聲明 FIELD 字段聲明(包括枚舉常量) LOCAL_VARIABLE 局部變量聲明 METHOD 方法聲明 PACKAGE 包聲明 PARAMETER 參數(shù)聲明 TYPE
注解的使用限定的例子:
1
2
3
4
|
@Target (ElementType.METHOD) public @interface MyAnnotation { String[] value1() default "abc" ; } |
9、在幫助文檔中加入注解:
要想在制作JavaDoc文件的同時(shí)將注解信息加入到API文件中,可以使用java.lang.annotation.Documented。
在自定義注解中聲明構(gòu)建注解文檔:
1
2
3
4
|
@Documented public @interface MyAnnotation { String[] value1() default "abc" ; } |
使用自定義注解:
1
2
3
4
5
6
|
public class AnnotationTest2 { @MyAnnotation (value1={ "a" , "b" }) public void execute(){ System.out.println( "method" ); } } |
10、在注解中使用繼承:
默認(rèn)情況下注解并不會(huì)被繼承到子類中,可以在自定義注解時(shí)加上java.lang.annotation.Inherited注解聲明使用繼承。
1
2
3
4
|
@Documented @Retention (value=RUNTIME) @Target (value=ANNOTATION_TYPE) public @interface Inherited |
指示注釋類型被自動(dòng)繼承。如果在注釋類型聲明中存在 Inherited 元注釋,并且用戶在某一類聲明中查詢該注釋類型,同時(shí)該類聲明中沒有此類型的注釋,則將在該類的超類中自動(dòng)查詢該注釋類型。此過程會(huì)重復(fù)進(jìn)行,直到找到此類型的注釋或到達(dá)了該類層次結(jié)構(gòu)的頂層 (Object) 為止。如果沒有超類具有該類型的注釋,則查詢將指示當(dāng)前類沒有這樣的注釋。
注意,如果使用注釋類型注釋類以外的任何事物,此元注釋類型都是無效的。還要注意,此元注釋僅促成從超類繼承注釋;對已實(shí)現(xiàn)接口的注釋無效。
總結(jié)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!
原文鏈接:https://gamwatcher.blog.csdn.net/article/details/8900679