Java註解是JDK1.5引入的一種註釋機制,它不會改變編譯器的編譯方式,Java編譯器對包含註解和不包含註解的代碼會生成相同的Java虛擬機指令。在實際應用中,註解只是一種標識,具體的操做須要藉助其餘工具來解析和處理。java
註解是使用@interface來定義的,全部註解都隱式的擴展自java.lang.annotation.Annotation接口。數組
以下MyFirstAnnotation是一個自定義註解,它具備兩個參數name和value,默認值都爲空字符串。在它的定義之上還標註了@Retention和@Target兩個元註解:函數
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyFirstAnnotation { String name() default ""; String value() default ""; }
註解參數類型是有限制的,必須限制在如下幾種類型中:工具
例如,若是不使用以上幾種,則會出現編譯錯誤:測試
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyFirstAnnotation { String name() default ""; Integer value() default 1;//包裝類型也不行,編譯錯誤 }
@Target和@Retention這種做用在註解上的註解,稱之爲元註解。經常使用的元註解以下:code
1.@Target,用於標識註解能夠標註的位置,接收一個ElementType[]參數。參數取值能夠參考ElementType枚舉類:繼承
public enum ElementType { /** 類、接口(包括註釋類型)或枚舉聲明 */ TYPE, /** 字段聲明(包括enum常量) */ FIELD, /** 方法聲明 */ METHOD, /** 形參聲明 */ PARAMETER, /** 構造函數聲明 */ CONSTRUCTOR, /** 局部變量聲明 */ LOCAL_VARIABLE, /** 註解類型聲明 */ ANNOTATION_TYPE, /** 包聲明 */ PACKAGE, /** * 類型參數聲明 * * @since 1.8 */ TYPE_PARAMETER, /** * 任何類型名稱 * * @since 1.8 */ TYPE_USE }
當指定的@Target和註解的使用位置不匹配時就會出現編譯錯誤,以下所示,@Target(ElementType.METHOD)表示MyFirstAnnotation註解只能用來標註方法,標註在類上就出現編譯錯誤:接口
//編譯錯誤 @MyFirstAnnotation public class Demo { //正確 @MyFirstAnnotation public void doSomeThing(){ } }
2.@Retention,用於標識註解能夠保留多久,接收一個RetentionPolicy參數,參數取值能夠參考RetentionPolicy枚舉類:字符串
public enum RetentionPolicy { /** * 表示註解只會存在於.java的源代碼文件中,不會保留到編譯後的.class文件中 */ SOURCE, /** * 表示註解能夠保留到.class文件中,可是不會被Java虛擬機所加載 */ CLASS, /** * 表示註解能夠保留到.class文件中,並由虛擬機加載 */ RUNTIME }
3.@Documented,表示這個註解能出如今javadoc中。get
4.@Inherited,表示當這個註解用於一個類的時候,可以自動的被它的子類繼承。
5.@Repeatable,表示這個註解能夠在同一個位置應用屢次。
默認狀況下,同一個位置添加多個重複註解會有編譯錯誤:
public class Demo { //編譯錯誤 @MyFirstAnnotation(name = "張三") @MyFirstAnnotation(name = "李四") @MyFirstAnnotation(name = "王五") public void doSomeThing(){ } }
能夠經過添加@Repeatable元註解來使@MyFirstAnnotation能重複使用。
首先須要建立一個容器註解@MyFirstAnnotations,容器註解@MyFirstAnnotations必需要有一個參數value,而且其類型爲MyFirstAnnotation[]:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyFirstAnnotations { MyFirstAnnotation[] value(); }
而後添加@Repeatable註解,並指定容器註解。
@Repeatable(MyFirstAnnotations.class) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyFirstAnnotation { String name() default ""; String value() default ""; }
關於註解的使用須要注意,註解參數是不能爲null的,默認值也是不能爲null。
定義註解@RepeatMethod,包含int類型參數value。
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RepeatMethod { int value() default 1; }
在doSomeThing方法上應用註解。若是要指定的註解參數爲value,而且沒有指定其餘的參數值時,能夠採用簡寫的方式,省略參數名和等號。
public class Demo { @RepeatMethod(5) public void doSomeThing(){ System.out.println("----註解測試----"); } }
經過反射獲取註解信息,而後作對應的處理,如假設@RepeatMethod註解的做用是重複調用被標註的方法,參數value是指定重複調用方法的次數:
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MyDemo { public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException { Class cla = Demo.class; Method[] methods = cla.getMethods(); Object demo = cla.newInstance(); for (Method method : methods){ //判斷方法上是否有標註@RepeatMethod註解 if(method.isAnnotationPresent(RepeatMethod.class)){ //獲取RepeatMethod註解的參數值 RepeatMethod repeatMethod = method.getAnnotation(RepeatMethod.class); for (int i = 0;i < repeatMethod.value(); i++) method.invoke(demo, null); } } } }
輸出結果:
----註解測試---- ----註解測試---- ----註解測試---- ----註解測試---- ----註解測試----