註解(Annotation)很重要,將來的開發模式都是基於註解的,JPA是基於註解的,Spring2.5以上都是基於註解的,Hibernate3.x之後也是基於註解的,如今的Struts2有一部分也是基於註解的了,註解是一種趨勢,如今已經有很多的人開始用註解了,註解是JDK1.5以後纔有的新特性java
JDK1.5以後內部提供的三個註解數組
@Deprecated 意思是「廢棄的,過期的」安全
@Override 意思是「重寫、覆蓋」ide
@SuppressWarnings 意思是「壓縮警告」工具
範例:註解的應用:開發工具
1 package cn.gacl.annotation; 2 /** 3 * 此類是用來演示註解(Annotation)的應用的,註解也是JDK1.5新增長的特性之一 4 * JDK1.5內部提供的三種註解是:@SuppressWarnings(":deprecation")、@Deprecated、@Override 5 * @author 孤傲蒼狼 6 * 7 */ 8 /** 9 * 類名的命名是有講究的,類名、屬性名、變量名通常是名詞,或者是形容詞+名詞,方法通常是動詞,或者是動詞+名詞, 10 * 以AnnotationTest做爲類名和以TestAnnotation做爲類名是有區別的, 11 * 前者是註解的測試,符合名詞的特徵,後者是測試註解,聽起來就是一個動做名稱,是方法的命名特徵 12 */ 13 public class AnnotationTest { 14 /** 15 * @param args 16 */ 17 @SuppressWarnings(":deprecation") 18 //這裏就是註解,稱爲壓縮警告,這是JDK內部自帶的一個註解,一個註解就是一個類,在這裏使用了這個註解就是建立了SuppressWarnings類的一個實例對象 19 public static void main(String[] args) { 20 System.runFinalizersOnExit(true); 21 //The method runFinalizersOnExit(boolean) from the type System is deprecated(過期的,廢棄的) 22 //這裏的runFinalizersOnExit()方法畫了一條橫線表示此方法已通過時了,不建議使用了 23 } 24 @Deprecated //這也是JDK內部自帶的一個註解,意思就是說這個方法已經廢棄了,不建議使用了 25 public static void sayHello(){ 26 System.out.println("hi,孤傲蒼狼"); 27 } 28 @Override //這也是JDK1.5以後內部提供的一個註解,意思就是要重寫(覆蓋)JDK內部的toString()方法 29 public String toString(){ 30 return "孤傲蒼狼"; 31 } 32 }
總結:註解(Annotation)至關於一種標記,在程序中加入註解就等於爲程序打上某種標記,沒有加,則等於沒有任何標記,之後,javac編譯器、開發工具和其餘程序能夠經過反射來了解你的類及各類元素上有無何種標記,看你的程序有什麼標記,就去幹相應的事,標記能夠加在包、類,屬性、方法,方法的參數以及局部變量上。測試
註解就至關於一個你的源程序要調用一個類,在源程序中應用某個註解,得事先準備好這個註解類。就像你要調用某個類,得事先開發好這個類。spa
自定義一個最簡單的註解:code
1 public @interface MyAnnotation{}
1 package cn.gacl.annotation; 2 import java.lang.annotation.ElementType; 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 import java.lang.annotation.Target; 6 /** 7 * 這是一個自定義的註解(Annotation)類 在定義註解(Annotation)類時使用了另外一個註解類Retention 8 * 在註解類上使用另外一個註解類,那麼被使用的註解類就稱爲元註解 9 * 10 * @author 孤傲蒼狼 11 * 12 */ 13 @Retention(RetentionPolicy.RUNTIME) 14 //Retention註解決定MyAnnotation註解的生命週期 15 @Target( { ElementType.METHOD, ElementType.TYPE }) 16 //Target註解決定MyAnnotation註解能夠加在哪些成分上,如加在類身上,或者屬性身上,或者方法身上等成分 17 /* 18 * @Retention(RetentionPolicy.SOURCE) 19 * 這個註解的意思是讓MyAnnotation註解只在java源文件中存在,編譯成.class文件後註解就不存在了 20 * @Retention(RetentionPolicy.CLASS) 21 * 這個註解的意思是讓MyAnnotation註解在java源文件(.java文件)中存在,編譯成.class文件後註解也還存在, 22 * 被MyAnnotation註解類標識的類被類加載器加載到內存中後MyAnnotation註解就不存在了 23 */ 24 /* 25 * 這裏是在註解類MyAnnotation上使用另外一個註解類,這裏的Retention稱爲元註解。 26 * Retention註解括號中的"RetentionPolicy.RUNTIME"意思是讓MyAnnotation這個註解的生命週期一直程序運行時都存在 27 */ 28 public @interface MyAnnotation { 29 }
把自定義的註解加到某個類上:對象
1 @ MyAnnotation 2 public class AnnotationUse{ 3 4 }
用反射測試進行測試AnnotationUse的定義上是否有@MyAnnotation
1 package cn.gacl.annotation; 2 @MyAnnotation 3 //這裏是將新建立好的註解類MyAnnotation標記到AnnotaionTest類上 4 public class AnnotationUse { 5 public static void main(String[] args) { 6 // 這裏是檢查Annotation類是否有註解,這裏須要使用反射才能完成對Annotation類的檢查 7 if (AnnotationUse.class.isAnnotationPresent(MyAnnotation.class)) { 8 /* 9 * MyAnnotation是一個類,這個類的實例對象annotation是經過反射獲得的,這個實例對象是如何建立的呢? 10 * 一旦在某個類上使用了@MyAnnotation,那麼這個MyAnnotation類的實例對象annotation就會被建立出來了 11 * 假設不少人考駕照,教練在有些學員身上貼一些綠牌子、黃牌子,貼綠牌子的表示送禮送得比較多的, 12 * 貼黃牌子的學員表示送禮送得比較少的,不貼牌子的學員表示沒有送過禮的,經過這個牌子就能夠標識出不一樣的學員 13 * 教官在考覈時一看,哦,這個學員是有牌子的,是送過禮給他的,優先讓有牌子的學員過,此時這個牌子就是一個註解 14 * 一個牌子就是一個註解的實例對象,實實在在存在的牌子就是一個實實在在的註解對象,把牌子拿下來(去掉註解)註解對象就不存在了 15 */ 16 MyAnnotation annotation = (MyAnnotation) AnnotationUse.class 17 .getAnnotation(MyAnnotation.class); 18 System.out.println(annotation);// 打印MyAnnotation對象,這裏輸出的結果爲:@cn.itcast.day2.MyAnnotation() 19 } 20 } 21 }
根據反射的測試的問題,引出@Retention元註解的講解:其三種取值:RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME分別對應:Java源文件(.java文件)---->.class文件---->內存中的字節碼
當在Java源程序上加了一個註解,這個Java源程序要由javac去編譯,javac把java源文件編譯成.class文件,在編譯成class時可能會把Java源程序上的一些註解給去掉,java編譯器(javac)在處理java源程序時,可能會認爲這個註解沒有用了,因而就把這個註解去掉了,那麼此時在編譯好的class中就找不到註解了, 這是編譯器編譯java源程序時對註解進行處理的第一種可能狀況,假設java編譯器在把java源程序編譯成class時,沒有把java源程序中的註解去掉,那麼此時在編譯好的class中就能夠找到註解,當程序使用編譯好的class文件時,須要用類加載器把class文件加載到內存中,class文件中的東西不是字節碼,class文件裏面的東西由類加載器加載到內存中去,類加載器在加載class文件時,會對class文件裏面的東西進行處理,如安全檢查,處理完之後獲得的最終在內存中的二進制的東西纔是字節碼,類加載器在把class文件加載到內存中時也有轉換,轉換時是否把class文件中的註解保留下來,這也有說法,因此說一個註解的生命週期有三個階段:java源文件是一個階段,class文件是一個階段,內存中的字節碼是一個階段,javac把java源文件編譯成.class文件時,有可能去掉裏面的註解,類加載器把.class文件加載到內存時也有可能去掉裏面的註解,所以在自定義註解時就可使用Retention註解指明自定義註解的生命週期,自定義註解的生命週期是在RetentionPolicy.SOURCE階段(java源文件階段),仍是在RetentionPolicy.CLASS階段(class文件階段),或者是在RetentionPolicy.RUNTIME階段(內存中的字節碼運行時階段),根據JDK提供的API能夠知道默認是在RetentionPolicy.CLASS階段 (JDK的API寫到:the retention policy defaults to RetentionPolicy.CLASS.)
下面看看@Deprecated、@Override、@SuppressWarnings這三個註解的@Retention註解的屬性值分別是什麼吧
Java API中是這樣定義的@Deprecated的
1 @Documented 2 @Retention(value=RUNTIME) 3 public @interface Deprecated
Java API中是這樣定義的@Override的
1 @Target(value=METHOD) 2 @Retention(value=SOURCE) 3 public @interface Override
@Override是給javac(java編譯器)看的,編譯完之後就@Override註解就沒有價值了,@Override註解在源代碼中有用,編譯成.class文件後@Override註解就沒有用了,所以@Override的Retention的屬性值是RetentionPolicy.SOURCE
Java API中是這樣定義的@SuppressWarnings的
1 @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) 2 @Retention(value=SOURCE) 3 public @interface SuppressWarnings
@SuppressWarnings是給javac(java編譯器)看的,編譯器編譯完java文件後,@SuppressWarnings註解就沒有用了,因此@SuppressWarnings的Retention的屬性值是RetentionPolicy.SOURCE
@Target元註解決定了一個註解能夠標識到哪些成分上,如標識在在類身上,或者屬性身上,或者方法身上等成分,@Target默認值爲任何元素(成分)
例如:
1 @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) 2 @Retention(value=SOURCE) 3 public @interface SuppressWarnings
註解能夠當作是一種特殊的類,既然是類,那天然能夠爲類添加屬性
語法:類型 屬性名();
1 package cn.gacl.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Retention(RetentionPolicy.RUNTIME) 9 //Retention註解決定MyAnnotation註解的生命週期 10 @Target( { ElementType.METHOD, ElementType.TYPE }) 11 public @interface MyAnnotation { 12 /** 13 * 定義基本屬性 14 * @return 15 */ 16 String color(); 17 }
其實從代碼的寫法上來看,註解更像是一種特殊的接口,註解的屬性定義方式就和接口中定義方法的方式同樣,而應用了註解的類能夠認爲是實現了這個特殊的接口
1 package cn.gacl.annotation; 2 3 @MyAnnotation(color="red")//應用MyAnnotation註解的color屬性 4 public class MyAnnotationTest { 5 public static void main(String[] args) { 6 /** 7 * 用反射方式得到註解對應的實例對象後,在經過該對象調用屬性對應的方法 8 */ 9 MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class); 10 System.out.println(annotation.color());//輸出red 11 } 12 }
語法:類型 屬性名() default 默認值;
package cn.gacl.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) //Retention註解決定MyAnnotation註解的生命週期 @Target( { ElementType.METHOD, ElementType.TYPE }) public @interface MyAnnotation { String color() default "blue";//爲屬性指定缺省值 }
1 package cn.gacl.annotation; 2 3 @MyAnnotation 4 public class MyAnnotationTest { 5 public static void main(String[] args) { 6 /** 7 * 用反射方式得到註解對應的實例對象後,在經過該對象調用屬性對應的方法 8 */ 9 MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class); 10 System.out.println(annotation.color());//輸出color屬性的默認值:blue 11 12 } 13 }
若是一個註解中有一個名稱爲value的屬性,且你只想設置value屬性(即其餘屬性都採用默認值或者你只有一個value屬性),那麼能夠省略掉「value=」部分。
例如:@SuppressWarnings("deprecation")
1 package cn.gacl.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Retention(RetentionPolicy.RUNTIME) 9 //Retention註解決定MyAnnotation註解的生命週期 10 @Target( { ElementType.METHOD, ElementType.TYPE }) 11 public @interface MyAnnotation { 12 String color() default "blue";//爲屬性指定缺省值 13 String value();//定義一個名稱爲value的屬性 14 }
1 package cn.gacl.annotation; 2 3 @MyAnnotation("孤傲蒼狼")//等價於@MyAnnotation(value="孤傲蒼狼") 4 public class MyAnnotationTest { 5 public static void main(String[] args) { 6 /** 7 * 用反射方式得到註解對應的實例對象後,在經過該對象調用屬性對應的方法 8 */ 9 MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class); 10 System.out.println(annotation.color());//輸出color屬性的默認值:blue 11 System.out.println(annotation.value()); 12 13 } 14 }
1 /** 2 * MetaAnnotation註解類爲元註解 3 * @author 孤傲蒼狼 4 * 5 */ 6 public @interface MetaAnnotation { 7 String value();//元註解MetaAnnotation設置有一個惟一的屬性value 8 }
爲註解添加一個註解類型的屬性,並指定註解屬性的缺省值:MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");
EumTrafficLamp.java
1 package cn.gacl.annotation; 2 /** 3 * 交通訊號燈顏色枚舉 4 * @author 孤傲蒼狼 5 * 6 */ 7 public enum EumTrafficLamp { 8 RED,//紅 9 YELLOW,//黃 10 GREEN//綠 11 }
MetaAnnotation.java
1 /** 2 * MetaAnnotation註解類爲元註解 3 * @author 孤傲蒼狼 4 * 5 */ 6 public @interface MetaAnnotation { 7 String value();//元註解MetaAnnotation設置有一個惟一的屬性value 8 }
MyAnnotation.java
1 package cn.gacl.annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 @Retention(RetentionPolicy.RUNTIME) 9 //Retention註解決定MyAnnotation註解的生命週期 10 @Target({ElementType.METHOD, ElementType.TYPE}) 11 public @interface MyAnnotation { 12 String color() default "blue";//爲屬性指定缺省值 13 /** 14 * 爲註解添加value屬性,這個value屬性很特殊,若是一個註解中只有一個value屬性要設置, 15 * 那麼在設置註解的屬性值時,能夠省略屬性名和等號不寫, 直接寫屬性值,如@SuppressWarnings("deprecation"), 16 * 這裏的MyAnnotation註解設置了兩個String類型的屬性,color和value, 17 * 由於color屬性指定有缺省值,value屬性又是屬於特殊的屬性,所以使用MyAnnotation註解時 18 * 能夠這樣使用MyAnnotation註解:"@MyAnnotation(color="red",value="xdp")" 19 * 也能夠這樣使用:"@MyAnnotation("孤傲蒼狼")",這樣寫就表示MyAnnotation註解只有一個value屬性要設置,color屬性採用缺省值 20 * 當一個註解只有一個value屬性要設置時,是能夠省略"value="的 21 */ 22 String value();//定義一個名稱爲value的屬性 23 //添加一個int類型數組的屬性 24 int[] arrayAttr() default {1,2,4}; 25 //添加一個枚舉類型的屬性,並指定枚舉屬性的缺省值,缺省值只能從枚舉類EumTrafficLamp中定義的枚舉對象中取出任意一個做爲缺省值 26 EumTrafficLamp lamp() default EumTrafficLamp.RED; 27 //爲註解添加一個註解類型的屬性,並指定註解屬性的缺省值 28 MetaAnnotation annotationAttr() default @MetaAnnotation("xdp"); 29 30 }
MyAnnotationTest.java
1 package cn.gacl.annotation; 2 /** 3 * 這裏是將新建立好的註解類MyAnnotation標記到AnnotaionTest類上, 4 * 並應用了註解類MyAnnotation中定義各類不一樣類型的的屬性 5 */ 6 @MyAnnotation( 7 color="red", 8 value="孤傲蒼狼", 9 arrayAttr={3,5,6}, 10 lamp=EumTrafficLamp.GREEN, 11 annotationAttr=@MetaAnnotation("gacl") 12 ) 13 public class MyAnnotationTest { 14 @MyAnnotation("將MyAnnotation註解標註到main方法上") 15 public static void main(String[] args) { 16 /** 17 * 這裏是檢查Annotation類是否有註解,這裏須要使用反射才能完成對Annotation類的檢查 18 */ 19 if(MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) { 20 /** 21 * 用反射方式得到註解對應的實例對象後,在經過該對象調用屬性對應的方法 22 * MyAnnotation是一個類,這個類的實例對象annotation是經過反射獲得的,這個實例對象是如何建立的呢? 23 * 一旦在某個類上使用了@MyAnnotation,那麼這個MyAnnotation類的實例對象annotation就會被建立出來了 24 */ 25 MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class); 26 System.out.println(annotation.color());//輸出color屬性的默認值:red 27 System.out.println(annotation.value());//輸出value屬性的默認值:孤傲蒼狼 28 System.out.println(annotation.arrayAttr().length);//這裏輸出的數組屬性的長度的結果爲:3,數組屬性有三個元素,所以數組的長度爲3 29 System.out.println(annotation.lamp());//這裏輸出的枚舉屬性值爲:GREEN 30 System.out.println(annotation.annotationAttr().value());//這裏輸出的註解屬性值:gacl 31 32 MetaAnnotation ma = annotation.annotationAttr();//annotation是MyAnnotation類的一個實例對象 33 System.out.println(ma.value());//輸出的結果爲:gacl 34 35 36 } 37 } 38 }