註解(Annotation)在java中應用很是普遍。它既能幫助咱們在編碼中減小錯誤,(好比最多見的Override註解),還能夠幫助咱們減小各類xml文件的配置,好比定義AOP切面用@AspectJ模式代替Schema模式,特別是最近接觸了一點Spring MVC,每次編寫Controller的時候用@RequestMapping(),@RequestParam,@ResponseBody等等。java
咱們所用的java中自帶的註解都是定義好了的,直接拿來用,它就能發揮做用。固然了,本身也能夠定義註解。數組
註解定義:app
public @interface 註解名 { //… }
能夠給註解中能夠定義「屬性」,暫且理解爲屬性吧,定義以下:框架
public @interface MyAnnotation { String hello(); // 定義了一個屬性名hello String world() default "world";// 定義了一個屬性名world,默認值爲「world」,注意類型匹配 int number();// 定義了一個屬性名爲number String[] value(); // 定義了一個屬性爲value的數組 }
後面必須有括號,修飾符只能爲public或abstract,不過通常都是默認不寫的。ide
當咱們定義一個註解時,它暗自的繼承了Annotation這個藉口。若是手動定義了一個Interface 並繼承了java.lang.annotation.Annotation,並不意味着定義了一個註解。註解只能經過@Interface方式定義。Annotation是一個接口而不是一個註解。編碼
使用方式:spa
1.當咱們對一個註解定義了多個屬性後,在使用該註解時,除了定義了默認值的屬性,其餘屬性都要賦值。固然,也能夠顯式的對含有默認值的屬性賦值。code
例如:xml
public class MyAnnotationTest{ private String name; @MyAnnotation(hello = "", number = 0, value = { "aa" },world="world1") public static void main(String[] args) { MyAnnotationTest test = new MyAnnotationTest(); test.method(); } @MyAnnotation(hello = "hello", number = 0, value = {"a"},world="aa") public void method(){ System.out.println("method"); } }
2.當一個註解只含有一個屬性且屬性名爲value時,咱們能夠簡化使用方式。對象
好比定義一個註解:
public @interface SingleAnnotation { String[] value(); }
在使用在註解時能夠簡化:
@SingleAnnotation("value") public void singleAnnotationMethod(){ }
註解基本的定義和使用差很少就這些了。接下來看看定義的註解爲何會生效。
@Retention註解
爲了更好的使用註解,java內置的這個註解也是須要了解的。
java.lang.annotation.Retention能夠告訴編譯器怎樣去對待和處理咱們自定義的註解。默認狀況下會將Annotation的信息留在class文件中,但不會被JVM讀取。
在使用Retention註解時,須要提供java.lang.annotation.RetentionPolicy的枚舉值。編譯器會根據設置不一樣的值來決定如何處理定義的註解。
RetentionPolicy定義以下:
public enum RetentionPolicy { SOURCE, //編譯程序丟棄該註解,表示他不會存在於class文件中 CLASS, //編譯程序將Annotation存在class文件中(缺省) RUNTIME //編譯程序將Annotation存在class文件中,可由JVM讀取 }
好比@SuppressWarnings註解,它所對應的@Retention(RetentionPolicy.SOURCE)是這樣設置的,由於它的做用是告知編譯程序來壓制警告,不必將這個信息存在於class文件中。
RetentionPolicy.RUNTIME:搭配反射機制,可讓註解被JVM讀出。
一個註解信息如何被JVM讀出:
1.將該註解加上 @Retention(value = RetentionPolicy.RUNTIME)。
1.得到一個類的class對象
2.得到這個類中被該註解修飾的方法或屬性。 AccessibleObject的isAnnotationPresent(Class<? extends Annotation> annotationClass)方法能夠判斷一個註解是否出現,因爲Field和Method類繼承了AccessibleObject,因此能夠判斷出一個類的方法或屬性是否有該註解。又由於Method實現了
AnnotatedElement ,因此method能夠獲得它對應的註解的Annotation對象,進而能夠獲取註解的相關信息。
下面給出例子:
首先給MyAnnotation註解 加上 @Retention(value = RetentionPolicy.RUNTIME)。
public class MyAnnotationTest{ public static void main(String[] args)throws Exception{ MyAnnotationTest test = new MyAnnotationTest(); Class<?> clazz = test.getClass(); Method[] methods = clazz.getMethods(); for(Method m : methods){ //該方法是否出現MyAnnotation註解,出現爲true,不然爲false if(m.isAnnotationPresent(MyAnnotation.class)){ MyAnnotation annotation = m.getAnnotation(MyAnnotation.class); String hello = annotation.hello(); int number = annotation.number(); String[] values = annotation.value(); String world = annotation.world(); m.invoke(test,new Object[]{}); System.out.println("annotation.hello():" + hello); System.out.println("annotation.number():" + number); System.out.println("annotation.value():" + values[0]); System.out.println("annotation.world():" + world); } } } @MyAnnotation(hello = "hello", number = 100, value = {"a"},world="aa") public void method(){ System.out.println("method"); } public void method2(){ System.out.println("method2"); } }
console 結果:
結果一目瞭然,可讓該方法執行,能夠拿到該註解的全部賦值狀況。
若是 MyAnnotation的Retention註解爲 @Retention(value = RetentionPolicy.CLASS) 或@Retention(value = RetentionPolicy.SOURCE),那麼method方法也不會執行,更不會獲取到MyAnnotation的先關信息了。
@Target註解
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
它也是用來註解咱們定義的註解。value爲ElementType類型的枚舉值。
ElementType定義:
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE }
好吧,不用解釋了,看註釋都知道每個值是什麼意思了。
若是一個註解被@Target直接,那麼該註解所修飾的類型將受到限制,若是修飾的類型不匹配編譯將會報錯。
表示MyAnnotation註解只能修飾方法,可根據ElementType 的值以此類推。
@Documented
它表示被修飾的註解將會生成到javadoc幫助文檔中。
@Inherited:容許子類繼承父類的註解。缺省狀況下子類並不會繼承父類中的Annotation.
就算java的原生註解,通常也是被這幾種註解中的一種或多種修飾,進而達到其功能。
總結:個其實java註解的原理仍是反射。在運行時,由於有了註解,利用反射機制在運行時纔會找到註解對應的方法,找到註解對應的值。值拿到了,方法也找到了,想幹什麼就幹什麼了,該幹什麼這通常應該是底層或框架作的事情。但我想應該就是這麼回事吧!