java annotation

一. 最常見的annotation
  • @Override:用在方法之上,用來告訴別人這一個方法是改寫父類的
  • @Deprecated:建議別人不要使用舊的API的時候用的,編譯的時候會用產生警告信息,可以設定在程序裏的所有的元素上.
  • @SuppressWarnings:暫時把一些警告信息消息關閉
  • @Entity:表示該類是可持久化的類
 
二. 設計一個自己的Annotation
      先看代碼再講話
1. 只有一個參數的Annotation實現
 
  1. package  chb.test.annotation;  
  2. import  java.lang.annotation.Documented;  
  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. @Target (ElementType.TYPE)  
  8. @Retention (RetentionPolicy.RUNTIME)  
  9. @Documented   
  10. public   @interface  MyAnnotation1 {  
  11.         String value();  
  12. }  
 
 
2. 有兩個參數的Annotation實現
 
  1. package  chb.test.annotation;  
  2. import  java.lang.annotation.Documented;  
  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. @Target (ElementType.METHOD)  
  8. @Retention (RetentionPolicy.RUNTIME)  
  9. @Documented   
  10. public   @interface  MyAnnotation2 {  
  11.         String description();  
  12.         boolean  isAnnotation();  
  13. }  
 
 
3. Annotation實驗類
 
  1. package  chb.test.annotation;  
  2. @MyAnnotation1 ( "this is annotation1" )  
  3. public   class  AnnotationDemo {  
  4.         @MyAnnotation2 (description= "this is annotation2" ,isAnnotation= true )  
  5.         public   void  sayHello(){  
  6.                 System.out.println("hello world!" );  
  7.         }  
  8. }  
 
 
4.Annotation測試說明類
 
  1. package  chb.test.annotation;  
  2. import  java.lang.reflect.Method;  
  3. import  org.junit.Test;  
  4. public   class  TestAnnotation {  
  5.         @Test   
  6.         public   void  test()  throws  ClassNotFoundException, SecurityException, NoSuchMethodException{  
  7.                 Class<?> cls = Class.forName("chb.test.annotation.AnnotationDemo" );  
  8.                 boolean  flag = cls.isAnnotationPresent(MyAnnotation1. class );  
  9.                 if (flag){  
  10.                         System.out.println("判斷類是annotation" );  
  11.                         MyAnnotation1 annotation1 = cls.getAnnotation(MyAnnotation1.class );  
  12.                         System.out.println(annotation1.value());  
  13.                 }  
  14.                   
  15.                 Method method = cls.getMethod("sayHello" );  
  16.                 flag = method.isAnnotationPresent(MyAnnotation2.class ) ;  
  17.                 if (flag){  
  18.                         System.out.println("判斷方法也是annotation" );  
  19.                         MyAnnotation2 annotation2 = method.getAnnotation(MyAnnotation2.class );  
  20.                         System.out.println(annotation2.description()+"/t" +annotation2.isAnnotation());  
  21.                 }  
  22.         }  
  23.           
  24. }  
 
 
實驗結果,控制檯打出如下信息:
 
判斷類是annotation
this is annotation1
判斷方法也是annotation
this is annotation2     true
 
三.簡介及說明
 
1. MyAnnotation1中的@Target(ElementType.TYPE)
      @Target裏面的ElementType是用來指定Annotation類型可以用在哪些元素上的.例如:
       TYPE(類型)、FIELD(屬性)、METHOD(方法)、PARAMETER(參數)、CONSTRUCTOR(構造函數)、LOCAL_VARIABLE(局部變量),、PACKAGE(包),其中的TYPE(類型)是指可以用在 Class,Interface,Enum和Annotation類型上。
2. MyAnnotation1中的@Retention(RetentionPolicy.RUNTIME)
      RetentionPolicy 共有三種策略,分別爲:
  • SOURCE:這個Annotation類型的信息只會保留在程序源碼裏,源碼如果經過了編譯之後,Annotation的數據就會消失,並不會保留在編譯好的.class文件裏面
  • CLASS:這個Annotation類型的信息保留在程序源碼裏,同時也會保留在編譯好的.class文件裏面,在執行的時候,並不會把這些信息加載到JVM中。注:默認策略爲CLASS類型
  • RUNTIME:表示在源碼、編譯好的.class文件中保留信息,在執行的時候會把這一些信息加載到JVM中去的
3. MyAnnotation1中的@Documented
目的就是將這一Annotation的信息顯示在JAVA API文檔上,如果沒有增加@Documented的話,JAVA API文檔上不會顯示相關annotation信息
 
4. MyAnnotation1中的@interface
   關鍵字,表示該類爲Annotation定義
5. MyAnnotation1中的 String value();
   表示有一個成員參數,名字爲value,訪問權爲默認(default)修飾符,注意以下兩點:
  • 訪問權只能用public和默認(default)修飾
  • 參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和String,Enum,Class,annotations等數據類型,以及這一些類型的數組
6.AnnotationDemo中的@MyAnnotation1("this is annotation1")
   因爲MyAnnotation1只有一個參數,因此可以直接在括號中寫上value值。注:如果Annotation只有一個參數,則建議最好將該參數名稱定義爲value
7.TestAnnotation中的cls.isAnnotationPresent(MyAnnotation1.class)
    判斷該類是否使用了MyAnnotation1的註釋
8. TestAnnotation中的MyAnnotation1 annotation1 = cls.getAnnotation(MyAnnotation1.class)
    返回該類針對MyAnnotation1的註釋
9. TestAnnotation中的method.isAnnotationPresent(MyAnnotation2.class)
    判斷該方法是否使用了MyAnnotation2的註釋

 
 
 

  (1) Annotation(註釋)JDK5.0及以後版本引入的。它可以用於創建文檔,跟蹤代碼中的依賴性,甚至執行基本編譯時檢查。註釋是以‘@註釋名在代碼中存在的,根據註釋參數的個數,我們可以將註釋分爲:標記註釋、單值註釋、完整註釋三類。它們都不會直接影響到程序的語義,只是作爲註釋(標識)存在,我們可以通過反射機制編程實現對這些元數據的訪問。另外,你可以在編譯時選擇代碼裏的註釋是否只存在於源代碼級,或者它也能在class文件中出現。

元數據的作用
如果要對於元數據的作用進行分類,目前還沒有明確的定義,不過我們可以根據它所起的作用,大致可分爲三類:

編寫文檔:通過代碼裏標識的元數據生成文檔。
代碼分析:通過代碼裏標識的元數據對代碼進行分析。

編譯檢查:通過代碼裏標識的元數據讓編譯器能實現基本的編譯檢查。

基本內置註釋

@Override

 

Java代碼
  1. package com.iwtxokhtd.annotation;  
  2. /** 
  3.  * 測試Override註解 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public class OverrideDemoTest {  
  8.   
  9.     //@Override  
  10.     public String tostring(){  
  11.         return "測試註釋";  
  12.     }  
  13. }  
package com.iwtxokhtd.annotation;
/**
 * 測試Override註解
 * @author Administrator
 *
 */
public class OverrideDemoTest {

	//@Override
	public String tostring(){
		return "測試註釋";
	}
}

 

 

 

@Deprecated的作用是對不應該在使用的方法添加註釋,當編程人員使用這些方法時,將會在編譯時顯示提示信息,它與javadoc裏的@deprecated標記有相同的功能,準確的說,它還不如javadoc @deprecated,因爲它不支持參數,使用@Deprecated的示例代碼示例如下:

 

Java代碼
  1. package com.iwtxokhtd.annotation;  
  2. /** 
  3.  * 測試Deprecated註解 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public class DeprecatedDemoTest {  
  8.      public static void main(String[] args) {  
  9.         //使用DeprecatedClass裏聲明被過時的方法  
  10.          DeprecatedClass.DeprecatedMethod();  
  11.      }  
  12. }  
  13. class DeprecatedClass{  
  14.     @Deprecated  
  15.     public static void DeprecatedMethod() {       
  16.       }   
  17. }  
package com.iwtxokhtd.annotation;
/**
 * 測試Deprecated註解
 * @author Administrator
 *
 */
public class DeprecatedDemoTest {
	 public static void main(String[] args) {
		//使用DeprecatedClass裏聲明被過時的方法
		 DeprecatedClass.DeprecatedMethod();
	 }
}
class DeprecatedClass{
	@Deprecated
	public static void DeprecatedMethod() {     
	  } 
}

 

@SuppressWarnings,其參數有:

deprecation,使用了過時的類或方法時的警告

unchecked,執行了未檢查的轉換時的警告

fallthrough,當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告

path,在類路徑、源文件路徑等中有不存在的路徑時的警告

serial,當在可序列化的類上缺少 serialVersionUID 定義時的警告

finally ,任何 finally 子句不能正常完成時的警告

all,關於以上所有情況的警告

 

Java代碼
  1. package com.iwtxokhtd.annotation;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class SuppressWarningsDemoTest {  
  7.   
  8.     public static List list=new ArrayList();  
  9.     @SuppressWarnings("unchecked")  
  10.     public void add(String data){  
  11.         list.add(data);  
  12.     }  
  13. }  
package com.iwtxokhtd.annotation;

import java.util.ArrayList;
import java.util.List;

public class SuppressWarningsDemoTest {

	public static List list=new ArrayList();
	@SuppressWarnings("unchecked")
	public void add(String data){
		list.add(data);
	}
}

 

(2)自定義註釋

它類似於新創建一個接口類文件,但爲了區分,我們需要將它聲明爲@interface,如下例:

  

Java代碼
  1. public @interface NewAnnotation {  
  2. }  
public @interface NewAnnotation {
}

 

使用自定義的註釋類型

 

Java代碼
  1. public class AnnotationTest {  
  2.     @NewAnnotation   
  3.     public static void main(String[] args) {  
  4.     }  
  5. }   
public class AnnotationTest {
    @NewAnnotation 
    public static void main(String[] args) {
    }
} 

 

 

爲自定義註釋添加變量

 

Java代碼
  1. public @interface NewAnnotation {   
  2.      String value();   
  3. }   
public @interface NewAnnotation { 
     String value(); 
} 

 

 

  

Java代碼
  1. public class AnnotationTest {   
  2.      @NewAnnotation("main method")   
  3.     public static void main(String[] args) {   
  4.         saying();   
  5.     }   
  6.     @NewAnnotation(value = "say method")   
  7.      public static void saying() {  
  8.      }  
  9. }   
public class AnnotationTest { 
     @NewAnnotation("main method") 
    public static void main(String[] args) { 
        saying(); 
    } 
    @NewAnnotation(value = "say method") 
     public static void saying() {
     }
} 

 

 

 

 定義一個枚舉類型,然後將參數設置爲該枚舉類型,並賦予默認值

  

Java代碼
  1. public @interface Greeting {     
  2. public enum FontColor{  
  3.        BLUE,RED,GREEN  
  4.     };  
  5.     String name();  
  6.     FontColor fontColor() default FontColor.RED;}    
  7. }  
public @interface Greeting {   
public enum FontColor{
	   BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;}  
}

 

 

這裏有兩種選擇,其實變數也就是在賦予默認值的參數上,我們可以選擇使用該默認值,也可以重新設置一個值來替換默認值

 

Java代碼
  1. @NewAnnonation("main method")  
  2.     public static void main(String[] args) {  
  3.             saying();     
  4.             sayHelloWithDefaultFontColor();     
  5.             sayHelloWithRedFontColor();     
  6.   
  7.     }  
  8.     @NewAnnonation("say method")  
  9.     public static  void saying(){  
  10.           
  11.     }  
  12.     //此時的fontColor爲默認的RED  
  13.     @Greeting(name="defaultfontcolor")  
  14.     public static void sayHelloWithDefaultFontColor() {     
  15.           
  16.     }  
  17.     //現在將fontColor改爲BLUE  
  18.     @Greeting(name="notdefault",fontColor=Greeting.FontColor.BLUE)  
  19.     public static void sayHelloWithRedFontColor() {     
  20.              
  21. }  
@NewAnnonation("main method")
	public static void main(String[] args) {
    	    saying();   
    	    sayHelloWithDefaultFontColor();   
    	    sayHelloWithRedFontColor();   

	}
    @NewAnnonation("say method")
    public static  void saying(){
    	
    }
    //此時的fontColor爲默認的RED
    @Greeting(name="defaultfontcolor")
    public static void sayHelloWithDefaultFontColor() {   
        
    }
    //現在將fontColor改爲BLUE
    @Greeting(name="notdefault",fontColor=Greeting.FontColor.BLUE)
    public static void sayHelloWithRedFontColor() {   
           
}

 

 

(3)註釋的高級應用

   限制註釋的使用範圍

   @Target指定ElementType屬性

  

Java代碼
  1.  package java.lang.annotation;     
  2. public enum ElementType {     
  3.   TYPE,     
  4.   // 用於類,接口,枚舉但不能是註釋  
  5.   FIELD,     
  6.   // 字段上,包括枚舉值    
  7.   METHOD,     
  8.   // 方法,不包括構造方法  
  9.   PARAMETER,     
  10.   // 方法的參數  
  11.   CONSTRUCTOR,     
  12.   //構造方法  
  13.   LOCAL_VARIABLE,     
  14.   // 本地變量或catch語句   
  15.   ANNOTATION_TYPE,     
  16.   // 註釋類型(無數據)    
  17.   PACKAGE     
  18.   // Java包    
  19. }    
 package java.lang.annotation;   
public enum ElementType {   
  TYPE,   
  // 用於類,接口,枚舉但不能是註釋
  FIELD,   
  // 字段上,包括枚舉值  
  METHOD,   
  // 方法,不包括構造方法
  PARAMETER,   
  // 方法的參數
  CONSTRUCTOR,   
  //構造方法
  LOCAL_VARIABLE,   
  // 本地變量或catch語句 
  ANNOTATION_TYPE,   
  // 註釋類型(無數據)  
  PACKAGE   
  // Java包  
}  

  

註解保持性策略

 

Java代碼
  1. //限制註解使用範圍  
  2. @Target({ElementType.METHOD,ElementType.CONSTRUCTOR})  
  3. public @interface Greeting {  
  4.   
  5.     //使用枚舉類型  
  6.     public enum FontColor{  
  7.        BLUE,RED,GREEN  
  8.     };  
  9.     String name();  
  10.     FontColor fontColor() default FontColor.RED;  
  11. }  
//限制註解使用範圍
@Target({ElementType.METHOD,ElementType.CONSTRUCTOR})
public @interface Greeting {

	//使用枚舉類型
	public enum FontColor{
	   BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;
}

 

Java編譯器編譯時,它會識別在源代碼裏添加的註釋是否還會保留,這就是RetentionPolicy。下面是Java定義的RetentionPolicy枚舉:

編譯器的處理有三種策略:

將註釋保留在編譯後的類文件中,並在第一次加載類時讀取它

將註釋保留在編譯後的類文件中,但是在運行時忽略它

按照規定使用註釋,但是並不將它保留到編譯後的類文件中

 

  

Java代碼
  1. package java.lang.annotation;     
  2. public enum RetentionPolicy {     
  3.   SOURCE,     
  4.   // 此類型會被編譯器丟棄    
  5.   CLASS,     
  6.   // 此類型註釋會保留在class文件中,但JVM會忽略它    
  7.   RUNTIME     
  8.   // 此類型註釋會保留在class文件中,JVM會讀取它     
  9. }    
package java.lang.annotation;   
public enum RetentionPolicy {   
  SOURCE,   
  // 此類型會被編譯器丟棄  
  CLASS,   
  // 此類型註釋會保留在class文件中,但JVM會忽略它  
  RUNTIME   
  // 此類型註釋會保留在class文件中,JVM會讀取它   
}  

  

Java代碼
  1. //讓保持性策略爲運行時態,即將註解編碼到class文件中,讓虛擬機讀取  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface Greeting {  
  4.   
  5.     //使用枚舉類型  
  6.     public enum FontColor{  
  7.        BLUE,RED,GREEN  
  8.     };  
  9.     String name();  
  10.     FontColor fontColor() default FontColor.RED;  
  11. }  
//讓保持性策略爲運行時態,即將註解編碼到class文件中,讓虛擬機讀取
@Retention(RetentionPolicy.RUNTIME)
public @interface Greeting {

	//使用枚舉類型
	public enum FontColor{
	   BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;
}

 

文檔化功能

Java提供的Documented元註釋跟Javadoc的作用是差不多的,其實它存在的好處是開發人員可以定製Javadoc不支持的文檔屬性,並在開發中應用。它的使用跟前兩個也是一樣的,簡單代碼示例如下:

 

Java代碼
  1. //讓它定製文檔化功能  
  2. //使用此註解時必須設置RetentionPolicy爲RUNTIME  
  3. @Documented  
  4. public @interface Greeting {  
  5.   
  6.     //使用枚舉類型  
  7.     public enum FontColor{  
  8.        BLUE,RED,GREEN  
  9.     };  
  10.     String name();  
  11.     FontColor fontColor() default FontColor.RED;  
  12. }  
//讓它定製文檔化功能
//使用此註解時必須設置RetentionPolicy爲RUNTIME
@Documented
public @interface Greeting {

	//使用枚舉類型
	public enum FontColor{
	   BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;
}

  

標註繼承

 

Java代碼
  1. //讓它允許繼承,可作用到子類  
  2. @Inherited  
  3. public @interface Greeting {  
  4.   
  5.     //使用枚舉類型  
  6.     public enum FontColor{  
  7.        BLUE,RED,GREEN  
  8.     };  
  9.     String name();  
  10.     FontColor fontColor() default FontColor.RED;  
  11. }  
//讓它允許繼承,可作用到子類
@Inherited
public @interface Greeting {

	//使用枚舉類型
	public enum FontColor{
	   BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;
}

 

 

(4)讀取註解信息

屬於重點,在系統中用到註解權限時非常有用,可以精確控制權限的粒度

 

Java代碼
  1. package com.iwtxokhtd.annotation;  
  2. import java.lang.annotation.Annotation;  
  3. import java.lang.reflect.Method;  
  4.   
  5. //讀取註解信息  
  6. public class ReadAnnotationInfoTest {  
  7.     public static void main(String[] args)throws Exception {  
  8.         //測試AnnotationTest類,得到此類的類對象  
  9.         Class c=Class.forName("com.iwtxokhtd.annotation.AnnotationTest");  
  10.         //獲取該類所有聲明的方法  
  11.         Method []methods=c.getDeclaredMethods();  
  12.         //聲明註解集合  
  13.         Annotation[] annotations;  
  14.         //遍歷所有的方法得到各方法上面的註解信息  
  15.         for(Method method:methods){  
  16.             //獲取每個方法上面所聲明的所有註解信息  
  17.             annotations=method.getDeclaredAnnotations();  
  18.             //再遍歷所有的註解,打印其基本信息  
  19.             for(Annotation an:annotations){  
  20.             System.out.println("方法名爲:"+method.getName()+" 其上面的註解爲:"+an.annotationType().getSimpleName());  
  21.                 Method []meths=an.annotationType().getDeclaredMethods();  
  22.                 //遍歷每個註解的所有變量  
  23.                 for(Method meth:meths){  
  24.                     System.out.println("註解的變量名爲:"+meth.getName());  
  25.                 }  
  26.                   
  27.             }  
  28.         }  
  29.   
  30.     }  
  31.   
  32. }  
package com.iwtxokhtd.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

//讀取註解信息
public class ReadAnnotationInfoTest {
	public static void main(String[] args)throws Exception {
		//測試AnnotationTest類,得到此類的類對象
		Class c=Class.forName("com.iwtxokhtd.annotation.AnnotationTest");
		//獲取該類所有聲明的方法
		Method []methods=c.getDeclaredMethods();
		//聲明註解集合
		Annotation[] annotations;
		//遍歷所有的方法得到各方法上面的註解信息
		for(Method method:methods){
			//獲取每個方法上面所聲明的所有註解信息
			annotations=method.getDeclaredAnnotations();
			//再遍歷所有的註解,打印其基本信息
			for(Annotation an:annotations){
			System.out.println("方法名爲:"+method.getName()+" 其上面的註解爲:"+an.annotationType().getSimpleName());
				Method []meths=an.annotationType().getDeclaredMethods();
				//遍歷每個註解的所有變量
				for(Method meth:meths){
					System.out.println("註解的變量名爲:"+meth.getName());
				}
				
			}
		}

	}

}

 

 


轉自:http://iwtxokhtd.javaeye.com/blog/359939
發佈了12 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章