註解(Annotation),實際上和屬性、方法同樣,都是一個類的組成部分,不過對於初學者來講仍是有點陌生的,由於註解是給別人用的,而屬性和方法都是本身用的,這就致使沒有對註解進行深刻的學習,而在使用別人框架的時候,才被迫去了解框架提供的註解的使用方法。java
註解的形式都是以@開頭,在微博微信中@Somebody是通知某人,而註解的@Info,則表示通知一件事(代表一種狀態),具體通知誰不去管,具體誰去用也無論,誰對這個註解感興趣誰來用。api
咱們從最簡單的例子提及,最經常使用的就是@Override,@Deprecated,@SuppressWarnings。若是按照上面的說法來講明,這三個註解都是給編譯器使用的。數組
@Override:代表這個方法是重寫的父類的方法,當你把@Override放到一個方法上時,編譯器會自動去父類中查找是否有相應的方法,若是沒有,說明註解使用錯誤,或者重寫的方法名、參數等寫錯了,那麼編譯器就會給出編譯錯誤,讓你去修改。微信
@Deprecated:代表這個屬性被棄用,當你使用它的時候,編譯器就會給出提醒。框架
@SuppressWarnings:代表這不是一個警告,那麼編譯器就不會把它當作警告給提示出來。ide
也就是說,註解的使用方便了別人去作某些事情,若是不用註解的話用配置文件也能夠,可是針對上面三個註解,若是寫在配置文件中,那麼編譯器要怎麼知道去哪一個配置文件中去讀,又要以怎樣的格式去讀,這都是一個問題,而使用註解聽從了一種約定大於配置的理念。學習
因此使用註解的時候就要明白這個註解是給誰用的,用做什麼。spa
而當你打算寫一個框架時,也能夠提供註解的方式給別人使用,這樣來講更方便,而對於你來講就要以解析註解的方式來代替讀取並解析配置文件的方式。設計
註解也是有相應的屬性的,也就是說當定義一個註解的時候指定註解的屬性。code
首先了解一下能夠被註解的位置有哪些,這些都在一個枚舉類:ElementType當中:
註解位置配合@Target使用,當只有一個位置時能夠這麼使用:
@Target(ElementType.ANNOTATION_TYPE)
當指定多個位置時,使用方法以下:
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
若是一個註解沒有指定註解位置,那麼它能夠應用於全部位置。
註解也是有相應的聲明週期的,也是封裝在一個枚舉類:RetentionPolicy中:
聲明週期配合@Retention來使用,使用方法以下:
@Retention(RetentionPolicy.RUNTIME)
通常來講對於編寫框架用的註解的生命週期都是RUNTIME。
註解和接口其實很類似,接口裏面的方法定義了行爲,註解的方法定義了屬性,下面先給一個例子:
public @interface MyAnnotation { //聲明屬性,可使用以下類型 String name(); String password() default "123"; int age() default 12; TimeUnit gender() default TimeUnit.SECONDS; Class<?> clazz(); int[] arr() default {1,2,3}; //爲了嵌套配置 Override my2(); }
簡單總結下:
當你提供一個註解供別人使用時,那麼對方可能將註解應用於容許的位置,並有可能賦值,而咱們沒法知道註解具體的位置,這時候只能經過反射加遍歷的方式來得到註解的位置。下面給出一個例子:
package yiwangzhibujian.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; public class UseAnnatation { public static void main(String[] args) throws Exception { Dog dog=new Dog(); Field[] fields = Dog.class.getFields(); for(Field field:fields){ DefaultValue annotation = field.getAnnotation(DefaultValue.class); if(annotation!=null){ String value = annotation.value(); field.set(dog, value); } } System.out.println(dog); } } class Dog{ @DefaultValue("little white") public String name; public int age; public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface DefaultValue{ String value(); }
這個例子作了以下事:
固然這個例子只是舉例說明註解的用法,默認值根本就不用這麼複雜的方式,若是用過Spring的話,應該知道自動注入的註解,實現原理就是經過這種方式。
除了一開始說的@Override,@Deprecated,@SuppressWarnings三個註解之外,jdk還有其餘註解,簡單來講,如今介紹的時候就會貼出源碼。
@Documented:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
這個註解用來代表,在生成api文檔的時候將註解的對象生成文檔。
@Inherited:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
被註解的註解,將會有被子類繼承。
@Repeatable:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { Class<? extends Annotation> value(); }
被註解的註解,能夠在一個屬性上重複使用。
@Native:
@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Native { }
代表一個字段引用的值可能來自於本地代碼,暫未找到具體示例,後續補上。
說到底,註解的使用方仍是很簡單的,難點在於提供給你註解的人是怎麼經過註解去達到他的目的的。若是你設計一個框架並提供註解給人使用,那麼你就要精通反射。不過通常狀況下是不多遇到須要自定義反射的場景,除非你設計一箇中間框架,別人經過你的框架來調用本身實現的類,就像Spring同樣。