Java 註解入門 元註解 註解解析 kaki的博客

Java 註解 註解解析 kaki的博客

  • 1. 註解的概述

  • 註解是JDK1.5的新特性。

  • 註解相當⼀一種標記,是類的組成部分,可以給類攜帶⼀一些額外的信息。

  • 標記(註解)可以加在包,類,字段,⽅方法,⽅方法參數以及局部變量量上。

  • 註解是給編譯器器或JVM看的,編譯器器或JVM可以根據註解來完成對應的功能。

註解 (Annotation) 相當於⼀一種標記,在程序中加⼊入註解就等於爲程序打上某種標記,以後, javac 編譯器器、開發⼯工具和其他程序可以通過反射來了了解你的類及各種元素上有⽆無何種
標記,看你的程 序有什什麼標記,就去⼲幹相應的事,標記可以加在包、類,屬性、⽅方法,⽅方法的參數以及局部變量量 上

2.註解的作用

註解的作用就是給程序帶入參數。
以下⼏幾個常⽤用操作中都使⽤用到了了註解:

  • 編譯檢查:@Override
    @Override:⽤用來修飾⽅方法聲明
    用來告訴編譯器器該⽅方法是重寫父類中的⽅方法,如果父類不不存在該方法,則編譯失敗。如 下圖
    在這裏插入圖片描述
  • 框架的配置(框架=代碼+配置)

3.常見註解

@author:⽤用來標識作者名,eclipse開發⼯工具默認的是系統⽤用戶名。
@version:⽤用於標識對象的版本號,適⽤用範圍:⽂文件、類、⽅方法。
@Override :⽤用來修飾⽅方法聲明,告訴編譯器器該⽅方法是重寫⽗父類中的⽅方法,如果⽗父類不不存在該⽅方 法,則編譯失敗。

4.自定義註解

  • 定義格式
public @interface 註解名{

} 
如:定義⼀一個名爲Student的註解 

public @interface Student {

} 

以上定義出來的註解就是⼀一個最簡單的註解了,但這樣的註解意義不大,因爲註解中沒有任何內 容,就好像我們定義⼀一個類而這個類中沒有任何成員變量量和方法⼀樣,這樣的類意義也是不大的, 所以在定義註解時會在⾥裏里⾯面添加⼀一些成員來讓註解功能更加強⼤大,這些成員就是屬性。接下來就看 看怎麼給註解添加屬性。

5.註解的屬性

  • 屬性的作用
    • 可以讓用戶在使用註解時傳遞參數,讓註解的功能更加強⼤
  • 屬性的格式
    • 格式1:數據類型 屬性名();
    • 格式2:數據類型 屬性名() default 默認值;
  • 屬性定義示例
    在這裏插入圖片描述
  • 屬性適用的數據類型
    • 八種基本數據類型(int,float,boolean,byte,double,char,long,short)
    • String類型,Class類型,枚舉類型,註解類型
    • 以上所有類型的⼀維數組

6.使用自定義註解

  • 定義註解
    1.定義⼀一個註解:Book
           包含屬性:String value() 書名
           包含屬性:double price() 價格,默認值爲 100
           包含屬性:String[] authors() 多位作者
public @interface Book {        
// 書名        
String value();        
// 價格        
double price() default 100;        
// 多位作者        
String[] authors(); 

}

7.使用註解

  • 定義類在成員⽅方法上使⽤用Book註解
/** 
  * @author kaki
  * @version 1.0 
  * @description 書架類 
  * @date 2018/1/26 
*/ 
public class BookShelf {      
    @Book(value = "西遊記",price = 998,authors = {"吳承恩","白求恩"})    
    public void showBook(){
         
    } 

}
  • 使用注意事項

8.特殊屬性value

  • 當註解中只有⼀一個屬性且名稱是value,在使用註解時給value屬性賦值可以直接給屬性值,無論 value是單值元素還是數組類型
// 定義註解Book 
public @interface Book {        
     // 書名
     String value(); 
}
// 使⽤用註解Book 
public class BookShelf {    
	
	@Book("西遊記")    
	public void showBook(){
	    
    }
     
}public class BookShelf {    

    @Book(value="西遊記")    
    public void showBook(){
    
    } 

}

  • 如果註解中除了value屬性還有其他屬性,且至少有⼀一個屬性沒有默認值,則在使⽤用註解給屬性賦 值時,value屬性名不不能省略。

在這裏插入圖片描述

9.問題分析

現在我們已經學會了如何定義註解以及如何使用註解了了,可能細⼼心的同學會發現⼀一個問題:我們定義的 註解是可以使⽤用在任何成員上的,比如剛剛Book註解的使用:

在這裏插入圖片描述

  1. 此時Book同時使用在了了類定義上或成員方法上,編譯器也沒有報錯,因爲默認情況下,註解可以 用在任何地方,比如類,成員方法,構造方法,成員變量等地⽅方
  2. 如果要限制註解的使⽤用位置怎麼辦?那就要學習⼀一個新的知識點:元註解。接下來就來看看什麼是 元註解以及怎麼使用

10. 註解之元註解

  • 元註解的概述
    1.Java API提供的註解
    2.專門用來定義註解的註解。
    3.任何Java官⽅方提供的非元註解的定義中都使⽤用到了元註解。

  • 常用元註解
    @Target
    @Retention

  • 元註解之@Target

    • 作用:指明此註解用在哪個位置,如果不寫默認是任何地⽅方都可以使用。
    • 可選的參數值在枚舉類ElemenetType中包括

TYPE: 用在類,接口上
FIELD:用在成員變量上
METHOD: 用在方法上
PARAMETER:用在參數上
CONSTRUCTOR:用在構造方法上
LOCAL_VARIABLE:用在局部變量上

  • 元註解之@Retention
    • 作用:定義該註解的生命週期(有效範圍)。
      • 可選的參數值在枚舉類型RetentionPolicy中包括

SOURCE:註解只存在於Java源代碼中,編譯生成的字節碼文件中就不存在了。
CLASS:註解存在於Java源代碼、編譯以後的字節碼文件中,運⾏行的時候內存中沒有,默認 值。
RUNTIME:註解存在於Java源代碼中、編譯以後的字節碼文件中、運行時內存中,程序可以 通過反射獲取該註解

  • 元註解使用示例

例 1在這裏插入圖片描述
例 2在這裏插入圖片描述

11.註解解析

  • 什麼是註解解析 ?

    通過Java技術獲取註解數據的過程則稱爲註解解析

  • 與註解解析相關的接口
    Anontation:所有註解類型的公共接口,類似所有類的父類是 Object。

    AnnotatedElement:定義了了與註解解析相關的⽅方法,常⽤用⽅方法以下四個:

boolean  isAnnotationPresent(Class annotationClass); 判斷當前對象是否有指定的注 解,有則返回true,否則返回false。
T   getAnnotation(Class annotationClass); 獲得當前對象上指定的註解對象。
Annotation[]  getAnnotations(); 獲得當前對象及其從⽗父類上繼承的所有的註解對象
Annotation[]   getDeclaredAnnotations();**獲得當前對象上所有的註解對象,不不包括⽗父類 的。

  • 獲取註解數據的原理
    註解作用在那個成員上,就通過反射獲得該成員的對象來得到它的註解。
          如註解作用在方法上,就通過方法(Method)對象得到它的註解
    在這裏插入圖片描述
          如註解作⽤用在類上,就通過Class對象得到它的註解
    在這裏插入圖片描述

  • 使用反射獲取註解的數據
    需求說明
    1. 定義註解Book,要求如下:

    • 包含屬性:String value() 書名
    • 包含屬性:double price() 價格,默認值爲 100
    • 包含屬性:String[] authors() 多位作者
    • 限制註解使⽤用的位置:類和成員⽅方法上
    • 指定註解的有效範圍:RUNTIME

    2. 定義BookStore類,在類和成員⽅方法上使⽤用Book註解
    3. 定義TestAnnotation測試類獲取Book註解上的數據
    代碼實現
    1. 註解Book
    在這裏插入圖片描述
    2. BookStore類
    在這裏插入圖片描述
    3. TestAnnotation類

/** 
  * @author kaki
  * @version 1.0 
  * @description com.kaki.annotation 
  * @date 2018/1/26 
  */ 
public class TestAnnotation {    
     public static void main(String[] args)  throws Exception{        
         System.out.println("---------獲取類上註解的數據----------");        
         test01();        
         System.out.println("---------獲取成員⽅方法上註解的數據----------");        
         test02();    
}
    /**     
      * 獲取BookStore類上使⽤用的Book註解數據     
      */    
     public static void test01(){        
	     // 獲得BookStore類對應的Class對象        
	     Class c = BookStore.class;        
	     // 根據註解Class對象獲取註解對象        
	     Book book = (Book) c.getAnnotation(Book.class); 
	     // 輸出book註解屬性值                	        
         System.out.println("書名:" + book.value()); 
         System.out.println("價格:" + book.price());        
         System.out.println("作者:" + Arrays.toString(book.authors()));            
   
     }
    /**     
      * 獲取BookStore類成員⽅方法buyBook使用的Book註解數據       */    
     public static void test02() throws Exception{       
	      // 獲得BookStore類對應的Class對象        
	      Class c = BookStore.class;       
	      // 獲得成員⽅方法buyBook對應的Method對象      
	      Method m = c.getMethod("buyBook");        
	      // 根據註解Class對象獲取註解對象        
	      Book book = (Book) m.getAnnotation(Book.class);        // 輸出book註解屬性值        
          
          System.out.println("書名:" + book.value());         
          System.out.println("價格:" + book.price());   
          System.out.println("作者:" +  Arrays.toString(book.authors()));   
      } 
}

輸出結果
在這裏插入圖片描述
存在問題分析

  • TestAnnotation類在獲取註解數據時處理得不夠嚴謹,假如出現下面的其中⼀種情況:
      1. 把BookStore類或成員⽅方法buyBook上的註解刪除。
      2. 將Book註解的有效範圍改爲:CLASS。
    再運行TestAnnotation類代碼則會出現空指針異常,如下圖所示:
    在這裏插入圖片描述
    原因分析如下圖
    在這裏插入圖片描述
    在這裏插入圖片描述

     解決方案

  • 在獲取註解對象時,先判斷是否有使⽤用註解,如果有,才獲取,否則就不用獲取
  • 修改TestAnnotation類的代碼,修改後如下
public class TestAnnotation {    

	public static void main(String[] args)  throws Exception{   
	
		System.out.println("---------獲取類上註解的數據----------");        
		test01();     
		
		System.out.println("---------獲取成員方法上註解的數據----------");        
		test02();    
	}
	
    /**     
	  * 獲取BookStore類上使用的Book註解數據     
	  */    
	public static void test01(){   
	
	    // 獲得BookStore類對應的Class對象        
		Class c = BookStore.class;        
		
		// 判斷BookStore類是否使用了Book註解        
		if(c.isAnnotationPresent(Book.class)) { 
		
			// 根據註解Class對象獲取註解對象            
			Book book = (Book) c.getAnnotation(Book.class);  
			
			// 輸出book註解屬性值            
			System.out.println("書名:" + book.value());            
			System.out.println("價格:" + book.price());            
			System.out.println("作者:" + Arrays.toString(book.authors()));        
		}    
	}
	
    /**     
	  * 獲取BookStore類成員方法buyBook使⽤用的Book註解數據     
	  */    
	public static void test02() throws Exception{        
	    // 獲得BookStore類對應的Class對象
        Class c = BookStore.class;       
		
		// 獲得成員方法buyBook對應的Method對象   		
		Method m = c.getMethod("buyBook");        
		
		// 判斷成員方法buyBook上是否使用了Book註解        
		if(m.isAnnotationPresent(Book.class)) {   
		
			// 根據註解Class對象獲取註解對象            
			Book book = (Book) m.getAnnotation(Book.class);    
			
			// 輸出book註解屬性值            
			System.out.println("書名:" + book.value());           
			System.out.println("價格:" + book.price());           
			System.out.println("作者:" + Arrays.toString(book.authors()));       
		}   
	} 
}

歡迎點贊關注收藏哦 ,碼雲搜索KakiNakajima

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章