Annotation(注解)簡單介紹:
注解大家印象最深刻的可能就是JUnit做單元測試,和各種框架里的使用了。
本文主要簡介一下注解的用法,下篇文章再深入的研究。
annotation并不直接影響代碼語義。可是它可以被看作類似程序的工具或者類庫。它會反過來對正在執行的程序語義有所影響。
annotation能夠從源文件,class文件或者以在執行時反射的多種方式被讀取
java注解系統自帶有主要下面幾個注解:
Override注解表示子類要重寫(override)父類的相應方法
Deprecated注解表示方法是不建議被使用的
Suppress Warnings注解表示抑制警告
怎樣自己定義注解:
僅僅須要使用@interface來定義一個注解,比如:
//使用@interface來聲明一個注解(實際上是自己主動繼承了java.lang.annotation.Annotation接口)
public @interface AnnotationTest {String value1() default "hello"; //為注解設置String類型的屬性Value1,并使用defalutkeyword設置默認值EnumTest value2(); //設置枚舉類型的value2String[] value3(); //設置數組類型的value3
}
怎樣來使用注解呢,例如以下: @AnnotationTest(value2 = EnumTest.age, value3={""})
public class AnnotationUsage {@AnnotationTest(value1 = "Test", value2 = EnumTest.name, value3={""})String test;@AnnotationTest(value1 = "Test", value2 = EnumTest.name, value3={""})public void method(){System.out.println("usage of Annotation");}
}
如上,注解能夠標注在屬性。方法。類上。 須要使用name=value這樣的賦值方式為屬性賦值,由于value1設置了默認屬性,所以能夠忽略,假設沒有設置默認值則全部的屬性都要一一賦值。
另一種特殊情況,假設注解里僅僅定義了一個屬性,名字是value,那么能夠直接賦值,不須要使用name=value這樣的賦值方式。例如以下:
public @interface AnnotationTest {String value();
}@AnnotationTest("test")
public void method(){System.out.println("usage of Annotation");
}
修飾注解的“注解”
注解也能夠加入注解的“注解”去修飾,經常使用的有下面兩個,一個是Retention。一個Target
Retention:
使用Retention必需要提供一個為java.lang.annotation.RetentionPolicy類型的的枚舉
RetentionPolicy枚舉有下面3個類型:
SOURCE:編譯程序時處理完Annotation信息后就完畢任務
CLASS:編譯程序將Annotation存儲于class文件里,不能夠由虛擬機讀入
RUNTIME:編譯程序將Annotation存儲于class文件里。能夠由虛擬機讀入
用這三種Retention的Prolicy能夠決定注解是從源文件。class文件或者以在執行時反射被讀取
關于Retention的樣例在最后
Target:
使用java.lang.annotation.Target能夠定義注解被使用的位置
相同,在使用時要指定一個java.lang.annotation.ElementType的枚舉值類型為他的“屬性”
ElementType枚舉的類型例如以下:
ANNOTATION_TYPE:適用于annotation
CONSTRUCTOR:適用于構造方法
FIELD:適用于field
LOCAL_VARIABLE:適用于局部變量
METHOD:適用于方法
PACKAGE:適用于package
PARAMETER:適用于method上的parameter
TYPE:適用于class,interface,enum
例如以下:定義一個注解MyTarget。設置Target類型為Method來修飾這個注解。這樣這個注解僅僅能標注在method的方法上
@Target(ElementType.METHOD)
public @interface MyTarget {String hello() default "hello";
}
@MyTarget //這里則會報錯,由于他標注在類上面了
public class MyTargetTest {@MyTarget //標注在方法上不會報錯public void doSomething(){System.out.println("hello world");}
}
getAnnotations(Class annotationType)獲取一個指定的annotation類型
getAnnotations() 獲取全部的Annotation
getDeclaredAnnotations()?獲取聲明過的全部Annotation
isAnnotationPresent(Class<? extends Annotation> annotationClass)這個annotation是否出現
通過這些方法,配合反射我們就能夠在程序執行時拿到注解的內容了。樣例例如以下:
@Retention(RetentionPolicy.RUNTIME) //定義一個注解。使用Retention標注為RUNTIME
public @interface MyAnnotation {String hello() default "hello";String world();
}
該注解被標示為runtime類型,表示該注解最后能夠保存在class文件里,并為java虛擬機在執行時讀取到
@Retention(RetentionPolicy.CLASS) //定義一個注解。Retention標注為RUNTIME
public @interface MyAnnotation2 {String hello() default "hello"; //設置默認值為hello
}
自己定義的還有一個注解Retention標示為class public class MyTest {@SuppressWarnings("unchecked") //java自帶的注解Retention的policy為SOURCE@Deprecated //java自帶的注解Retention的policy為RUNTIME@MyAnnotation(Name="Dean", Age="25") //自己定義的注解Retention的policy為RUNTIME@MyAnnotation2 //自己定義的注解Retention的policy為CLASSpublic void TestMethod() {System.out.println("this is a method");}
}
定義一個TestMethod方法。給他標示了4個注解。當中2個java自帶的,2個我們自己定義的。注解的的Retention屬性各不同樣。
以下定義一個測試類來驗證結果:
public static void main(String[] args) throws Exception {MyTest myTest = new MyTest();//通過反射得到TestMethod方法Class<MyTest> c = MyTest.class;Method method = c.getMethod("TestMethod", new Class[]{});//AnnotatedElement接口中的方法isAnnotationPresent(),推斷傳入的注解類型是否存在if (method.isAnnotationPresent(MyAnnotation.class)) {method.invoke(myTest, new Object[]{});//AnnotatedElement接口中的方法getAnnotation(),獲取傳入注解類型的注解MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);//拿到注解中的屬性String name = myAnnotation.Name();String age = myAnnotation.Age();System.out.println("name:"+name +" age:"+age);}System.out.println("-----------------------------------");//AnnotatedElement接口中的方法getAnnotations(),獲取全部注解Annotation[] annotations = method.getAnnotations();//循環注解數組打印出注解類型的名字for (Annotation annotation : annotations) {System.out.println(annotation.annotationType().getName());}}
打印結果為: this is a methodname:Dean ? age:25
-----------------------------------
java.lang.Deprecated
gxy.text.annotation.MyAnnotation
切割線上:介紹了怎樣使用AnnotatedElement接口中的方法和反射去調用注解
切割線下:證明了僅僅有定義了Retention的Policy為Runtime的注解才干夠被反射讀取出來
下一篇文章分析一下在JUnit中反射與注解的使用和原理