1. 程式人生 > >annotation(@[email protected])詳解

annotation(@[email protected])詳解

一、註解:深入理解JAVA註解

  要深入學習註解,我們就必須能定義自己的註解,並使用註解,在定義自己的註解之前,我們就必須要了解Java為我們提供的元註解和相關定義註解的語法。

1、元註解(meta-annotation):

元註解的作用就是負責註解其他註解。Java5.0定義了4個標準的meta-annotation型別,它們被用來提供對其它 annotation型別作說明。Java5.0定義的元註解:
    [email protected],
    [email protected],
    [email protected],
    [email protected]


  這些型別和它們所支援的類在java.lang.annotation包中可以找到。下面我們看一下每個元註解的作用和相應分引數的使用說明。

@Target:

   @Target說明了Annotation所修飾的物件範圍:Annotation可被用於 packages、types(類、介面、列舉、Annotation型別)、型別成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數)。在Annotation型別的宣告中使用了target可更加明晰其修飾的目標。

 作用:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用於描述構造器
    2.FIELD:用於描述域
    3.LOCAL_VARIABLE:用於描述區域性變數
    4.METHOD:用於描述方法
    5.PACKAGE:用於描述包
    6.PARAMETER:用於描述引數
    7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告

  使用例項:  

複製程式碼

@Target(ElementType.TYPE)
public @interface Table {
    /**
     * 資料表名稱註解,預設值為類名稱
     * @return
     */
    public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {

}

複製程式碼

註解Table 可以用於註解類、介面(包括註解型別) 或enum宣告,而註解NoDBColumn僅可用於註解類的成員變數。

@Retention:

  @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在原始碼中,而被編譯器丟棄;而另一些卻被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機器忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命週期”限制。

  作用:表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在原始檔中有效(即原始檔保留)
    2.CLASS:在class檔案中有效(即class保留)
    3.RUNTIME:在執行時有效(即執行時保留)

  Retention meta-annotation型別有唯一的value作為成員,它的取值來自java.lang.annotation.RetentionPolicy的列舉型別值。具體例項如下:

複製程式碼

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}

複製程式碼

 Column註解的的RetentionPolicy的屬性值是RUTIME,這樣註解處理器可以通過反射,獲取到該註解的屬性值,從而去做一些執行時的邏輯處理

  @Documented:

  @Documented用於描述其它型別的annotation應該被作為被標註的程式成員的公共API,因此可以被例如javadoc此類的工具文件化。Documented是一個標記註解,沒有成員。

複製程式碼

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}

複製程式碼

@Inherited:

@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的型別是被繼承的。如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。

  注意:@Inherited annotation型別是被標註過的class的子類所繼承。類並不從它所實現的介面繼承annotation,方法並不從它所過載的方法繼承annotation。

  當@Inherited annotation型別標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation型別的annotation時,反射程式碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation型別被發現,或者到達類繼承結構的頂層。

  例項程式碼:

複製程式碼

/**
 * 
 * @author peida
 *
 */
@Inherited
public @interface Greeting {
    public enum FontColor{ BULE,RED,GREEN};
    String name();
    FontColor fontColor() default FontColor.GREEN;
}

複製程式碼

自定義註解:

  使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面,由編譯程式自動完成其他細節。在定義註解時,不能繼承其他的註解或介面。@interface用來宣告一個註解,其中的每一個方法實際上是聲明瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別(返回值型別只能是基本型別、Class、String、enum)。可以通過default來宣告引數的預設值。

  定義註解格式:
  public @interface 註解名 {定義體}

註解引數的可支援資料型別:

    1.所有基本資料型別(int,float,boolean,byte,double,char,long,short)
    2.String型別
    3.Class型別
    4.enum型別
    5.Annotation型別
    6.以上所有型別的陣列

  Annotation型別裡面的引數該怎麼設定: 
  第一,只能用public或預設(default)這兩個訪問權修飾.例如,String value();這裡把方法設為defaul預設型別;   
  第二,引數成員只能用基本型別byte,short,char,int,long,float,double,boolean八種基本資料型別和 String,Enum,Class,annotations等資料型別,以及這一些型別的陣列.例如,String value();這裡的引數成員就為String;  
  第三,如果只有一個引數成員,最好把引數名稱設為"value",後加小括號.例:下面的例子FruitName註解就只有一個引數成員。

  簡單的自定義註解和使用註解例項:

複製程式碼

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果名稱註解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}

複製程式碼

複製程式碼

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果顏色註解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 顏色列舉
     * @author peida
     *
     */
    public enum Color{ BULE,RED,GREEN};
    
    /**
     * 顏色屬性
     * @return
     */
    Color fruitColor() default Color.GREEN;

}

複製程式碼

複製程式碼

package annotation;

import annotation.FruitColor.Color;

public class Apple {
    
    @FruitName("Apple")
    private String appleName;
    
    @FruitColor(fruitColor=Color.RED)
    private String appleColor;
    
    
    
    
    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }
    public String getAppleColor() {
        return appleColor;
    }
    
    
    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }
    public String getAppleName() {
        return appleName;
    }
    
    public void displayName(){
        System.out.println("水果的名字是:蘋果");
    }
}

複製程式碼

註解元素的預設值:

註解元素必須有確定的值,要麼在定義註解的預設值中指定,要麼在使用註解時指定,非基本型別的註解元素的值不可為null。因此, 使用空字串或0作為預設值是一種常用的做法。這個約束使得處理器很難表現一個元素的存在或缺失的狀態,因為每個註解的宣告中,所有元素都存在,並且都具有相應的值,為了繞開這個約束,我們只能定義一些特殊的值,例如空字串或者負數,一次表示某個元素不存在,在定義註解時,這已經成為一個習慣用法。例如:

複製程式碼

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果供應者註解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * 供應商編號
     * @return
     */
    public int id() default -1;
    
    /**
     * 供應商名稱
     * @return
     */
    public String name() default "";
    
    /**
     * 供應商地址
     * @return
     */
    public String address() default "";
}

複製程式碼

定義了註解,並在需要的時候給相關類,類屬性加上註解資訊,如果沒有響應的註解資訊處理流程,註解可以說是沒有實用價值。如何讓註解真真的發揮作用,主要就在於註解處理方法,下一步我們將學習註解資訊的獲取和處理!

二、註解的使用:

 第一步:新建一個annotation,名字為:MyAnnotation.java。

複製程式碼

package com.dragon.test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by gmq on 2015/9/10.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{

    String hello () default "hello";
    String world();
}

複製程式碼

第二步:建立一個MyTest.java 來使用上面的annotation。

複製程式碼

package com.dragon.test.annotation;

/**
 * Created by gmq on 2015/9/10.
 */
public class MyTest
{

    @MyAnnotation(hello = "Hello,Beijing",world = "Hello,world")
    public void output() {
        System.out.println("method output is running ");
    }
}

複製程式碼

第三步:用反射機制來呼叫註解中的內容

複製程式碼

package com.dragon.test.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 用反射機制來呼叫註解中的內容
 * Created by gmq on 2015/9/10.
 */
public class MyReflection
{
    public static void main(String[] args) throws Exception
    {
        // 獲得要呼叫的類
        Class<MyTest> myTestClass = MyTest.class;
        // 獲得要呼叫的方法,output是要呼叫的方法名字,new Class[]{}為所需要的引數。空則不是這種
        Method method = myTestClass.getMethod("output", new Class[]{});
        // 是否有型別為MyAnnotation的註解
        if (method.isAnnotationPresent(MyAnnotation.class))
        {
            // 獲得註解
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            // 呼叫註解的內容
            System.out.println(annotation.hello());
            System.out.println(annotation.world());
        }
        System.out.println("----------------------------------");
        // 獲得所有註解。必須是runtime型別的
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations)
        {
            // 遍歷所有註解的名字
            System.out.println(annotation.annotationType().getName());
        }
    }
}

複製程式碼

輸出:

Hello,Beijing
Hello,world
----------------------------------
com.dragon.test.annotation.MyAnnotation

相關推薦

annotation(@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="75271001101b011c1a1b35211407121001">[email&#160;protected]a>)

一、註解:深入理解JAVA註解   要深入學習註解,我們就必須能定義自己的註解,並使用註解,在定義自己的註解之前,我們就必須要了解Java為我們提供的元註解和相關定義註解的語法。 1、元註解(meta-annotation): 元註解的作用就是負責註解其他註解。Java

shell腳本中的$# $0 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f8dcb8">[email&#160;protected]a> $* $$ $! $?的意義

腳本 $* width 上一個 pre shell int .cn height 轉載自:http://www.cnblogs.com/davygeek/p/5670212.html 今天學寫腳本遇到一些變量不認識,在此做下記錄。 變量 含義 $0 當前腳本的文件

shell中$*與<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b296f2">[email&#160;protected]a>的區別

劃分 位置 一個 這也 差異 獨立 [email protected] 情況 雙引號 $*所有的位置參數,被作為一個單詞 註意:"$*"必須被""引用 [email protected] 與$*同義,但是每個參數都是一個獨立的""引用字串,這就意味著參數

Spring4.0系列<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aa9f87eae9c5c4cec3dec3c5c4cbc6">[email&#160;protected]a>

one window 標識 cto ace ted ada bsp 布爾 這篇文章介紹Spring 4的@Conditional註解。在Spring的早期版本你可以通過以下方法來處理條件問題: 3.1之前的版本,使用Spring Expression Langua

Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email&#160;protected]a>***註解的工作原理

sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="297a595b40474e69685c5d465e405b4c4d">[email&#160;protected]a>註解與自動裝配(轉發)

配置 調用方法 support autowired 信息 ann over 反射機制 test 1 配置文件的方法我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中註入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 se

linux bash Shell特殊變數:Shell $0, $#, $*, <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8aaeca">[email&#160;protected]a>, $?

在linux下配置shell引數說明 前面已經講到,變數名只能包含數字、字母和下劃線,因為某些包含其他字元的變數有特殊含義,這樣的變數被稱為特殊變數。  例如,$ 表示當前Shell程序的ID,即pid,看下面的程式碼: [[email protected] /]$ ec

spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="62000d0d16222103010a0703000e07">[email&#160;protected]a>中value的理解

先看原始碼 /** * Names of the caches in which method invocation results are stored. * <p>Names may be used to determine the target cache (or cac

{<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="733e3c3f3f2a342136363d203323213c273c3d3e323a3f5d303c3e">[email&#160;protecte

近日,復旦解密安全團隊發現GandCrab4.0活躍度提升,跟蹤到多起GandCrab4.0變種勒索事件,現釋出安全預警,提醒廣大使用者預防GandCrab4.0勒索。 目前復旦解密已經可以成功解密GandCrab4.0變種採用RSA+AES加密演算法 mg中毒檔案可以在一個小時解決.電話151691214

Springboot註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="260b0b666549485254494a4a4354">[email&#160;protected]a>和@RestCon

1.使用@Controller 註解,在對應的方法上,檢視解析器可以解析return 的jsp,html頁面,並且跳轉到相應頁面;若返回json等內容到頁面,則需要加@ResponseBody註解 [email protected]註解,相當於@[email protected

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b2c3e391b33">[email&#160;protected]a>,c小總結

問題0:元素內聯元素,行內元素,行內塊元素.         內聯: 寬高M,P都有效         行內元素:無寬高,內容撐開,M,P左右有效  

SQL Server資料庫mdf檔案中了勒索病毒<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc9f8e858c889998a39d8f9d9293bc9f939f97">[email&#160;p

SQL,資料庫,勒索病毒,mdf檔案中毒,[email protected]_email *SQL Server資料庫mdf檔案中了勒索病毒[email protected]_email。副檔名變為[email protected]_email SQL Serv

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5400313a273b2632383b2379142032">[email&#160;protected]a>_export

Tensorflow經常看到定義的函式前面加了“@tf_export”。例如,tensorflow/python/platform/app.py中有: @tf_export('app.run') def run(main=None, argv=None): """Runs the progr

手把手教你搭建React Native 開發環境 - ios篇 (React <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="eda38c99849b88adddc3d8d8c3d9">[email&#

由於之前我是h5的,沒接觸過ios和安卓, 也不瞭解xcode配置,所以 建議學reace-native之前還是先去了解一下ios和安卓開發環境搭建等問題。 環境下載及配置 nodejs:https://nodejs.org/en/download/ 設定淘寶映象 $ npm con

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4978382833093e3a3179797878">[email&#160;protected]a>

function changeSpan(){         var f = document.getElementById("file1").files;         &nb

SpringBoot學習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b7e8f7e7c5d8c7d2c5c3cee4d8c2c5d4d2">[email&#160;protected]a>&am

文章目錄 @PropertySource:載入指定的配置檔案 @ImportResource:匯入Spring的配置檔案,讓配置檔案裡面的內容生效; @Bean @PropertySource:載入指定的配置檔案

eclipse支援@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="95d2f0e1e1f0e7d5c6f0e1e1f0e7">[email&#160;protected]a>註解使用 -轉載

1. 下載lombok.jar 2.將下載的lombok.jar放在你的eclipse安裝目錄下,如圖: 3.修改eclipse.ini檔案,新增如下兩行配置:   -Xbootclasspath/a:lombok.jar -javaage

無法解析的外部符號 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1e41497770537f77705e2f28">[email&#160;protected]a>,該符號在函式 ___tmai

#include using namespace std; int main() { cout <<“This is a C++ program.”; return 0; } 1>------ 已啟動生成: 專案: hello1, 配置: Debug Win32 ---

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ce9eb7baa6a1a08ea4afb8af">[email&#160;protected]a>@C 比較

對所有的程式語言,他們的最後的目的其實就是兩種:提高硬體的執行效率和提高程式設計師的開發效率。 遺憾的是,這兩點是不可能並存的!你只能選一樣。在提高硬體的執行效率這一方面,C語言沒有競爭者!舉個簡單的例子,實現一個列表,C語言用陣列int a[3],經過編譯以後變成了(基地址+偏移量)的方式。對