1. 程式人生 > >Java自定義註解的使用場景和原理

Java自定義註解的使用場景和原理

什麼是註解?

      對於很多初次接觸的開發者來說應該都有這個疑問?Annontation是Java5開始引入的新特徵,中文名稱叫註解。它提供了一種安全的類似註釋的機制,用來將任何的資訊或元資料(metadata)與程式元素(類、方法、成員變數等)進行關聯。為程式的元素(類、方法、成員變數)加上更直觀更明瞭的說明,這些說明資訊是與程式的業務邏輯無關,並且供指定的工具或框架使用。Annontation像一種修飾符一樣,應用於包、型別、構造方法、方法、成員變數、引數及本地變數的宣告語句中。
  Java註解是附加在程式碼中的一些元資訊,用於一些工具在編譯、執行時進行解析和使用,起到說明、配置的功能。註解不會也不能影響程式碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。

註解的用處:

      1、生成文件。這是最常見的,也是java 最早提供的註解。常用的有@param @return 等
      2、跟蹤程式碼依賴性,實現替代配置檔案功能。比如Dagger 2依賴注入,未來java開發,將大量註解配置,具有很大用處;
      3、在編譯時進行格式檢查。如@override 放在方法前,如果你這個方法並不是覆蓋了超類方法,則編譯時就能檢查出。

註解的原理:

  註解本質是一個繼承了Annotation的特殊介面,其具體實現類是Java執行時生成的動態代理類。而我們通過反射獲取註解時,返回的是Java執行時生成的動態代理物件$Proxy1。通過代理物件呼叫自定義註解(介面)的方法,會最終呼叫AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。

元註解:

java.lang.annotation提供了四種元註解,專門註解其他的註解(在自定義註解的時候,需要使用到元註解):
   @Documented –註解是否將包含在JavaDoc中
   @Retention –什麼時候使用該註解
   @Target –註解用於什麼地方
   @Inherited – 是否允許子類繼承該註解

  1.)@Retention– 定義該註解的生命週期
  ●   RetentionPolicy.SOURCE : 在編譯階段丟棄。這些註解在編譯結束之後就不再有任何意義,所以它們不會寫入位元組碼。@Override, @SuppressWarnings都屬於這類註解。


  ●   RetentionPolicy.CLASS : 在類載入的時候丟棄。在位元組碼檔案的處理中有用。註解預設使用這種方式
  ●   RetentionPolicy.RUNTIME : 始終不會丟棄,執行期也保留該註解,因此可以使用反射機制讀取該註解的資訊。我們自定義的註解通常使用這種方式。

  2.)Target – 表示該註解用於什麼地方。預設值為任何元素,表示該註解用於什麼地方。可用的ElementType引數包括
  ● ElementType.CONSTRUCTOR:用於描述構造器
  ● ElementType.FIELD:成員變數、物件、屬性(包括enum例項)
  ● ElementType.LOCAL_VARIABLE:用於描述區域性變數
  ● ElementType.METHOD:用於描述方法
  ● ElementType.PACKAGE:用於描述包
  ● ElementType.PARAMETER:用於描述引數
  ● ElementType.TYPE:用於描述類、介面(包括註解型別) 或enum宣告

 3.)@Documented–一個簡單的Annotations標記註解,表示是否將註解資訊新增在java文件中。

 4.)@Inherited – 定義該註釋和子類的關係
     @Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的型別是被繼承的。如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。

常見標準的Annotation:

  1.)Override
      java.lang.Override是一個標記型別註解,它被用作標註方法。它說明了被標註的方法過載了父類的方法,起到了斷言的作用。如果我們使用了這種註解在一個沒有覆蓋父類方法的方法時,java編譯器將以一個編譯錯誤來警示。
  2.)Deprecated
     Deprecated也是一種標記型別註解。當一個型別或者型別成員使用@Deprecated修飾的話,編譯器將不鼓勵使用這個被標註的程式元素。所以使用這種修飾具有一定的“延續性”:如果我們在程式碼中通過繼承或者覆蓋的方式使用了這個過時的型別或者成員,雖然繼承或者覆蓋後的型別或者成員並不是被宣告為@Deprecated,但編譯器仍然要報警。
 3.)SuppressWarnings
     SuppressWarning不是一個標記型別註解。它有一個型別為String[]的成員,這個成員的值為被禁止的警告名。對於javac編譯器來講,被-Xlint選項有效的警告名也同樣對@SuppressWarings有效,同時編譯器忽略掉無法識別的警告名。
  @SuppressWarnings(“unchecked”)

自定義註解:

自定義註解類編寫的一些規則:
  1. Annotation型定義為@interface, 所有的Annotation會自動繼承java.lang.Annotation這一介面,並且不能再去繼承別的類或是介面.
  2. 引數成員只能用public或預設(default)這兩個訪問權修飾
  3. 引數成員只能用基本型別byte,short,char,int,long,float,double,boolean八種基本資料型別和String、Enum、Class、annotations等資料型別,以及這一些型別的陣列.
  4. 要獲取類方法和欄位的註解資訊,必須通過Java的反射技術來獲取 Annotation物件,因為你除此之外沒有別的獲取註解物件的方法
  5. 註解也可以沒有定義成員, 不過這樣註解就沒啥用了
PS:自定義註解需要使用到元註解

自定義註解例項:

FruitName.java

複製程式碼
 1 import java.lang.annotation.Documented;
 2 import java.lang.annotation.Retention;
 3 import java.lang.annotation.Target;
 4 import static java.lang.annotation.ElementType.FIELD;
 5 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 6 
 7 /**
 8  * 水果名稱註解
 9  */
10 @Target(FIELD)
11 @Retention(RUNTIME)
12 @Documented
13 public @interface FruitName {
14     String value() default "";
15 }
複製程式碼

FruitColor.java

複製程式碼
 1 import java.lang.annotation.Documented;
 2 import java.lang.annotation.Retention;
 3 import java.lang.annotation.Target;
 4 import static java.lang.annotation.ElementType.FIELD;
 5 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 6 
 7 /**
 8  * 水果顏色註解
 9  */
10 @Target(FIELD)
11 @Retention(RUNTIME)
12 @Documented
13 public @interface FruitColor {
14     /**
15      * 顏色列舉
16      */
17     public enum Color{ BLUE,RED,GREEN};
18     
19     /**
20      * 顏色屬性
21      */
22     Color fruitColor() default Color.GREEN;
23 
24 }
複製程式碼

FruitProvider.java

複製程式碼
 1 import java.lang.annotation.Documented;
 2 import java.lang.annotation.Retention;
 3 import java.lang.annotation.Target;
 4 import static java.lang.annotation.ElementType.FIELD;
 5 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 6 
 7 
 8 /**
 9  * 水果供應者註解
10  */
11 @Target(FIELD)
12 @Retention(RUNTIME)
13 @Documented
14 public @interface FruitProvider {
15     /**
16      * 供應商編號
17      */
18     public int id() default -1;
19     
20     /**
21      * 供應商名稱
22      */
23     public String name() default "";
24     
25     /**
26      * 供應商地址
27      */
28     public String address() default "";
29 }
複製程式碼

FruitInfoUtil.java

複製程式碼
 1 import java.lang.reflect.Field;
 2 
 3 /**
 4  * 註解處理器
 5  */
 6 public class FruitInfoUtil {
 7     public static void getFruitInfo(Class<?> clazz){
 8         
 9         String strFruitName=" 水果名稱:";
10         String strFruitColor=" 水果顏色:";
11         String strFruitProvicer="供應商資訊:";
12         
13         Field[] fields = clazz.getDeclaredFields();
14         
15         for(Field field :fields){
16             if(field.isAnnotationPresent(FruitName.class)){
17                 FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
18                 strFruitName=strFruitName+fruitName.value();
19                 System.out.println(strFruitName);
20             }
21             else if(field.isAnnotationPresent(FruitColor.class)){
22                 FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
23                 strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
24                 System.out.println(strFruitColor);
25             }
26             else if(field.isAnnotationPresent(FruitProvider.class)){
27                 FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
28                 strFruitProvicer=" 供應商編號:"+fruitProvider.id()+" 供應商名稱:"+fruitProvider.name()+" 供應商地址:"+fruitProvider.address();
29                 System.out.println(strFruitProvicer);
30             }
31         }
32     }
33 }
複製程式碼

Apple.java

複製程式碼
 1 import test.FruitColor.Color;
 2 
 3 /**
 4  * 註解使用
 5  */
 6 public class Apple {
 7     
 8     @FruitName("Apple")
 9     private String appleName;
10     
11     @FruitColor(fruitColor=Color.RED)
12     private String appleColor;
13     
14     @FruitProvider(id=1,name="陝西紅富士集團",address="陝西省西安市延安路89號紅富士大廈")
15     private String appleProvider;
16     
17     public void setAppleColor(String appleColor) {
18         this.appleColor = appleColor;
19     }
20     public String getAppleColor() {
21         return appleColor;
22     }
23     
24     public void setAppleName(String appleName) {
25         this.appleName = appleName;
26     }
27     public String getAppleName() {
28         return appleName;
29     }
30     
31     public void setAppleProvider(String appleProvider) {
32         this.appleProvider = appleProvider;
33     }
34     public String getAppleProvider() {
35         return appleProvider;
36     }
37     
38     public void displayName(){
39         System.out.println("水果的名字是:蘋果");
40     }
41 }
複製程式碼

FruitRun.java

複製程式碼
1 /**
2  * 輸出結果
3  */
4 public class FruitRun {
5     public static void main(String[] args) {
6         FruitInfoUtil.getFruitInfo(Apple.class);
7     }
8 }
複製程式碼

執行結果是:

 水果名稱:Apple
 水果顏色:RED
 供應商編號:1 供應商名稱:陝西紅富士集團 供應商地址:陝西省西安市延安路89號紅富士大廈

參考連結:
[1]http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html
[2]http://www.cnblogs.com/whoislcj/p/5671622.html
[3]http://blog.csdn.net/lylwo317/article/details/52163304

相關推薦

Java定義註解的使用場景原理

什麼是註解?       對於很多初次接觸的開發者來說應該都有這個疑問?Annontation是Java5開始引入的新特徵,中文名稱叫註解。它提供了一種安全的類似註釋的機制,用來將任何的資訊或元資料(metadata)與程式元素(類、方法、成員變數等)進行關聯。為程式的元素(類、方法、成員變數)加上更直觀更明

Java定義註解(原理API)初探

    今天稍稍學習了下註解,關於註解,我想大家都不陌生,目前可能在hibernate配置中可能會用的多一點,在JPA中也會用到。我想說的是學習註解可以幫助我們更好的理解註解在框架中(比如hibernate和Spirng等)的應用。     Annotation是JDK5版本以來的新特性。目前在JavaSE

java定義註解解析及相關場景實現

註解(Annotation)是java1.5之後提供的一種語法。其主要作用是編譯檢查(比如@override)和程式碼分析(通過程式碼中添加註解,利用註解解析器對添加了註解的程式碼進行分析,獲取想要的結果,一般自定義的註解都是這一種功能)。 1.1 JDK提供的註解 JDK提供的

JAVA定義註解的使用定義

 最近有所瞭解到自定義註解的應用,因此學習了一下,在專案後臺介面開發中,資料的傳輸經常有對資料內容格式及一些資訊規則的校驗,應用註解在資料進入後臺的開始使用自定義註解是一種比較可靠的方案。 一、註解的概念及分類        1.首先我們來看一下什麼是註解:        

java定義註解以及原理

import java.util.Arrays; import java.util.List; import com.puhui.flowplatform.manage.filter.RightFilter; import org.springframework.aop.BeforeAdvice; impo

Java定義註解執行時靠反射獲取註解

<span style="font-family:SimHei;font-size:18px;color:#663300;"><strong><span class="bh_code_a_Java_keywords">public</span> <span

JAVA定義註解提取註解資訊

第一節:定義註解       定義新的Annotation型別使用@interface關鍵字(在原有interface關鍵字前增加@符號)。定義一個新的Annotation型別與定義一個介面很像,例如: public @interface Test{ } 定義完該Annot

Java定義註解 springMVC攔截器 配合使用記錄系統操作日誌的案例

自定義註解的用法, 好多人不知道, 在這裡, 程式碼的註釋中, 我已經詳細的介紹了, 另外就是很多人不知道自定義註解如何使用, 這裡配合springMVC攔截器, 做一個非常實用的案例. 案例: 記錄系統操作的日誌 首先是定義註解: package cn.wxy.ssm

Java定義註解反射校驗數據

sda new out 格式 是否 本地 imp 使用範圍 數據類型 package com.annotations.ecargo; import java.lang.annotation.ElementType; import java.lang.annotati

java定義註解

不包含 doc 1.2 color 子類 局部變量 ati 包含 ant Java註解是附加在代碼中的一些元信息,用於一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annot

java 定義註解

tar 基本用法 而且 最簡 ida outline plain 現在 傳播 參考鏈接:https://blog.csdn.net/hbzyaxiu520/article/details/6212969 JAVA自定義註釋(Target,Retention,Document

Java 定義註解&通過反射獲取類、方法、屬性上的註解

反射 JAVA中的反射是執行中的程式檢查自己和軟體執行環境的能力,它可以根據它發現的進行改變。通俗的講就是反射可以在執行時根據指定的類名獲得類的資訊。   註解的定義 註解通過 @interface 關鍵字進行定義。 /** * 自定義註解 *

Java定義註解之元註解(meta-annotation)Target、Retention、Documented、Inherited介紹

元註解:   元註解的作用就是負責註解其他(如:自定義)註解,用來對其它 annotation型別作說明。Java定義了4個標準的meta-annotation型別:    [email protected]    [email protected

java定義註解2】java定義註解結合Spring AOP

      承接上一篇,註解應用於屬性,本篇定義了一個用於方法的註解,結合Spring AOP 實現 切面程式設計。       以下demo演示使用了SpringBoot,與SSM中使用方式大致相同,效果如下: 1、自定義註解(用

java定義註解1】java定義註解-屬性

        關於自定義註解,以前專案種應用的不多,最近看新專案過程中發現了挺多自定義註解相關內容,使用起來比較巧妙,於是 總結了兩種方式,記錄如下:         第一種:結合反射進行屬性注入,程式碼如下:

java 定義註解驗證 (僅限於實體屬性值上的註解

資源下載地址:http://download.csdn.net/detail/weilai_zhilu/9761533   該驗證主要包含三部分 註解驗證類 註解處理方法類 實體類 測試類 第一部分:註解驗證類(此部分暫時只寫了三個驗證類) 下面

java定義註解在service層不生效原因

在做對資料加redis快取時,我這面採用了Spring-Aop的方式通過切面將資料存放在redis中,但是業務場景是,當前端呼叫了controller層的介面時,會走一些簽名校驗,如果校驗過了才會真正呼叫service層去取資料,所以我自己定義的註解載入controlle

java定義註解學習(一)_demo小練習

自定義註解 現在大家開發過程中,經常會用到註解。 比如@Controller 等等,但是有時候也會碰到自定義註解,在開發中公司的記錄日誌就用到了自定義註解。身為渣渣猿還是有必要學習下自定義註解的。 這篇我們先寫一個簡單的註解列子,不會立馬介紹各種什麼元註解。從例子中感受下註解的作用 定義個註解 packa

java定義註解學習(二)_註解詳解

上篇文章,我們簡單的實現了一個自定義註解,相信大家對自定義註解有了個簡單的認識,這篇,這樣介紹下註解中的元註解和內值註解 整體圖示 內建註解 @Override 重寫覆蓋 這個註解大家應該經常用到,主要在子類重寫父類的方法,比如toString()方法 package com.kevin.demo;

java定義註解學習(三)_註解解析及應用

上篇文章已經介紹了註解的基本構成資訊。這篇文章,主要介紹註解的解析。畢竟你只聲明瞭註解,是沒有用的。需要進行解析。主要就是利用反射機制在執行時進行檢視和利用這些資訊 常用方法彙總 在Class、Field、Method、Constructor中都有如下方法: //獲取所有的註解 public Annota