Annotation

  從JDK1.5開始,Java就增長了Annotation這個新的功能,這種特性被稱爲元數據特性,同時也被稱爲註釋。html

  系統內建的Annotation:java

  提醒:如下這三個系統內建的Annotation位於java.lang包下linux

  1.@Override,相信你們對這個比較熟悉,若是咱們要重寫一個類的方法的時候,要加上這個註解,可是不少人會反問,不加也是沒問題的,可是咱們必須考慮到的是程序的正確性,若是你自己的意圖是重寫這個方法,可是你在寫的時候把方法名寫錯了,那麼這就不是重寫了,也改變了意圖,因此在重寫的方法上加上這個註解是防患於未然,也是明確的告訴別人我這個方法是重寫的,如何我寫錯方法名,那麼這個註解也會提醒我。數組

  2.@Deprecated,表示這個程序元素很危險或者存在更好的選擇,不鼓勵採用這種元素。ide

 

 1 @Deprecated
 2 public class DeprecatedDemo {
 3 
 4     @Deprecated
 5     public static final String name = "xujianguo";
 6     
 7     @Deprecated
 8     public void print() {
 9         System.out.println("This is the deprecated method");
10     }
11 }

  上面這個類說明了@Deprecated註解也是用在類上,成員屬性上,還有方法上,這個類用起來不會報錯,但會有警告的信息,表示你所用的東西已通過時了。工具

  3.@SuppressWarnings,表示取消顯示指定的編譯器警告,經過這個註解咱們能夠取消一個沒必要要的警告,如泛型警告和過期警告,經過查看API文檔咱們能夠發現,該Annotation下有一個value的屬性,返回值一個String類型的數組,具體爲:public abstract String[] value,這個屬性實際上是一個警告集,裏面用放的是@SuppressWarnings能夠壓制的警告。spa

  警告集:code

關鍵字 關鍵字
deprecation 使用了不同意使用的類或者方法的警告
unchecked 執行了未檢查的轉換警告,如泛型操做中沒有指定泛型
fallthrough 當switch程序塊執行到下種狀況時沒有break語句的警告
path 在類路徑、源文件路徑等中有着不存在路徑時的警告
serial 當在可序列化類上缺乏serialVersionUID定義時的警告
finally 任何finally子句不能完成時的警告
all 關於以上全部的警告

  下面演示一個壓制deprecatation和unchecked警告的Demo:htm

 

 1 /**
 2  * 該類實現了序列化接口,若無serialVersionUID會出現警告
 3  * @author Guo
 4  */
 5 @SuppressWarnings({"serial", "unchecked"})
 6 public class SuppressWarningsDemo implements Serializable{
 7     
 8     public static void main(String[] args) {
 9         
10         /**
11          * 沒有指定泛型,出現警告
12          * @author Guo
13          */
14         List<String> list = new ArrayList();
15     }
16 }

 

  自定義Annotation:對象

  定義本身的Annotation很是簡單,就像定義一個接口那樣:

1 [public] @interface MyAnnotation {
2 
3 }

  格式很簡單,一個Annotation可能接收各類參數,就像SuppressWarnings註解那樣,裏面能夠接收一個數組,下面咱們介紹一個它參數定義:

  1.基本變量,能夠是String類型的,也能夠是int類型的,格式:public 類型 變量名();

  2.數組類型,數組的定義格式也是大同小異:public 類型[] 變量名();

  3.枚舉類型,經過定義枚舉類型,就能夠限定註解裏面的內容,格式:格式:public enum 變量名();

  4.默認值,在Annotation中寫好默認值,在別的類上使用註解的時候就能夠不用寫值了,格式:public 類型 變量名() default 默認值;

  下面簡單演示一下,你們加深一下印象:

 1 enum MyEnum {
 2     xp, win7, linux;
 3 }
 4 
 5 public @interface MyAnnotation {
 6 
 7     public String name() default "xujianguo";
 8     public int age() default 20;
 9     public String[] array();
10     public MyEnum system() default MyEnum.linux;
11 }
12 
13 class Test {
14 
15     @MyAnnotation(name="zyp", age=20, array = {"zhou", "yan", "ping"}, system=MyEnum.win7)
16     public static void main(String[] args) {
17         System.out.println("Just Test");
18     }
19 }

  如今咱們要討論一個問題,你自定義好的就能在JVM跑嗎,其實你看看API中系統內建的三個Annotation,它們都使用了一個註解@Retention,這個註解位於java.lang.annotation包下,其實這個包下還有幾個Annotation,咱們也介紹一個,不太重點的是@Retention:

  1.@Documented,指示某一類型的註釋將經過 javadoc 和相似的默認工具進行文檔化。應使用此類型來註釋這些類型的聲明:其註釋會影響由其客戶端註釋的元素的使用。若是類型聲明是用Documented 來註釋的,則其註釋將成爲註釋元素的公共 API 的一部分。簡單的說就是用了這個註解,你之後用該Annotation的時候在上面加上註釋會被記錄到文檔上。

  2.@Inherited,指示註釋類型被自動繼承。若是在註釋類型聲明中存在 Inherited元註釋,而且用戶在某一類聲明中查詢該註釋類型,同時該類聲明中沒有此類型的註釋,則將在該類的超類中自動查詢該註釋類型。此過程會重複進行,直到找到此類型的註釋或到達了該類層次結構的頂層(Object) 爲止。若是沒有超類具備該類型的註釋,則查詢將指示當前類沒有這樣的註釋。簡單的說就是這個註解至關於extends啊,父類若是有了某個註解,那個這個註解在子類中也是擁有的,經過反射也能夠拿到註解上的信息。

  3.@Target,指示註釋類型所適用的程序元素的種類。若是註釋類型聲明中不存在 Target 元註釋,則聲明的類型能夠用在任一程序元素上。若是存在這樣的元註釋,則編譯器強制實施指定的使用限制。簡單的說這個註解就是限制咱們的Annotation能夠用在什麼地方,它有個value屬性,是ElementType類型的,ElementType中規定如下幾種範圍:

範圍

描述

ANNOTATION_TYPE

只能用在註釋聲明上

CONSTRUCTOR

只能用在構造方法上

FIELD

只能用在字段的聲明上

LOCAL_VARIABLE

只能用在局部變量的聲明上

METHOD

只能用在方法的聲明上

PACKAGE

只能用在包的聲明上

PARAMETER

只能用在參數的聲明上

TYPE

只能用在類、接口、枚舉類型上

  提醒:其實這些限制的範圍是能夠疊加的,例如,你的Annotation想在類或者方法上使用,能夠這麼寫:@Target(ElementType.TYPE, ElementType.METHOD)

  4.@Retention,指示註釋類型的註釋要保留多久。這個註釋有個value的屬性,屬性的類型爲RetentionPolicy,而RetentionPolicy裏面有三個常變量,咱們一塊兒來看看這三個常變量。

範圍 描述
SOURCE 此Annotation的信息只會保存在程序源文件中(java文件),不會保留在編譯好的文件中(class文件)
CLASS

此Annotation的信息保留在程序源文件(java文件)和編譯好的文件中(class文件),使用此類的時候

Annotation的信息不會被加載到JVM中,若是一個Annotation沒有聲明使用什麼範圍,這個就是默認範圍。

RUNTIME 此Annotation的信息會保留在源文件、類文件中,還會被加載到JVM中

  很明確的看出RUNTIME纔是咱們想要的菜,由於咱們要利用Annotation去獲取一些信息,咱們也來看看咱們系統內建的Annotation會屬於哪些呢?@Override採用的是Retention(value=RetentionPolicy.SOURCE),@Deprecated採用的是Retention(value=RetentionPolicy.RUNTIME),@SuppressWarnings採用的也是Retention(value=RetentionPolicy.SOURCE),總結一下,一個能真正對咱們來講起做用的Annotation應該這樣定義:

1 @Retention(value=RetentionPolicy.RUNTIME)
2 public @interface MyAnnotation {
3 
4     public String name() default "xujianguo";
5     public int age() default 20;
6     public String[] array();
7     public MyEnum system() default MyEnum.linux;
8 }

   

  Annotation與反射

  說到Annotation的應用,則不會離開反射,在Class類中存在如下幾種跟Annotation操做相關的方法:

方法 描述
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 若是存在該元素的指定類型的註釋,則返回這些註釋,不然返回 null

public Annotation[] getAnnotations()

返回此元素上存在的全部註釋
public Annotation[] getDeclaredAnnotations() 返回直接存在於此元素上的全部註釋。
public boolean isAnnotation() 判斷元素是否表示一個註釋
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 若是指定類型的註釋存在於此元素上,則返回 true,不然返回 false

   下面我自定義一個Annotation,用這個Annotation來模仿JUnit的@Test註解,同時自定義的這個Annotation也有屬性,要將這個屬性的值拿出來:

  自定義的Annotation-TestSimulation:

1 @Retention(value=RetentionPolicy.RUNTIME)
2 public @interface TestSimulation {
3     public String author() default "xujianguo";
4 }

  運用註解的類AnnotationDemo類:

 1 public class AnnotationDemo {
 2 
 3     @TestSimulation(author="zhouyanping")
 4     public void print() {
 5         System.out.println("This is the method of print");
 6     }
 7     
 8     public void say() {
 9         System.out.println("This is the method of say");
10     }
11     
12     @TestSimulation
13     public void coding() {
14         System.out.println("This is the method of coding");
15     }
16 }

  進行反射解析的AnnotationUtil類:

 1 public class AnnotationUtil {
 2 
 3     public static void main(String[] args) throws Exception {
 4         
 5         /**
 6          * 反射類的對象和拿出一個方法組
 7          * @author Guo
 8          */
 9         Class clazz = Class.forName("com.xujianguo.test.AnnotationDemo");
10         Object object = clazz.newInstance();
11         Method[] methods = clazz.getMethods();
12         
13         for(Method method : methods) {
14             
15             /**
16              * 對方法上的註解進行覈對
17              * @author Guo
18              */
19             if(method.isAnnotationPresent(TestSimulation.class)) {
20                 
21                 /**
22                  * 拿到指定的Annotation並獲取相應的信息
23                  * @author Guo
24                  */
25                 TestSimulation ts = method.getAnnotation(TestSimulation.class);
26                 System.out.println(ts.author());
27                 method.invoke(object);
28             }
29         }
30     }
31 }
相關文章
相關標籤/搜索