Annotation(註解)基礎知識

本文轉發自Jason’s Blog原文連接 http://www.jasongj.com/2016/01/17/Java1_註解Annotationjava

概念

Annotation是Java5開始引入的特性。它提供了一種安全的相似於註釋和Java doc的機制。實事上,Annotation已經被普遍用於各類Java框架,如Spring,Jersey,JUnit,TestNG。註解至關因而一種嵌入在程序中的元數據,可使用註解解析工具或編譯器對其進行解析,也能夠指定註解在編譯期或運行期有效。這些元數據與程序業務邏輯無關,而且是供指定的工具或框架使用的。數組

Meta Annotation

元註解的做用就是負責註解其餘註解。Java5定義了4個標準的Meta Annotation類型,它們被用來提供對其它 Annotation類型做說明。安全

@Target

@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了@Target可更加明晰其修飾的目標。bash

@Target做用:用於描述註解的使用範圍,即被描述的註解能夠用在什麼地方框架

@Target取值(ElementType)ide

  • CONSTRUCTOR:用於描述構造器
  • FIELD:用於描述域
  • LOCAL_VARIABLE:用於描述局部變量
  • METHOD:用於描述方法
  • PACKAGE:用於描述包
  • PARAMETER:用於描述參數
  • TYPE:用於描述類、接口(包括註解類型) 或enum聲明

@Retention

@Retention定義了該Annotation的生命週期:某些Annotation僅出如今源代碼中,而被編譯器丟棄;而另外一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另外一些在class被裝載時將被讀取(請注意並不影響class的執行,由於Annotation與class在使用上是被分離的)。@Retention有惟一的value做爲成員。工具

@Retention做用:表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)spa

@Retention取值來自java.lang.annotation.RetentionPolicy的枚舉類型值.net

  • SOURCE:在源文件中有效(即源文件保留)
  • CLASS:在class文件中有效(即class保留)
  • RUNTIME:在運行時有效(即運行時保留)

@Documented

@Documented用於描述其它類型的annotation應該被做爲被標註的程序成員的公共API,所以能夠被例如javadoc此類的工具文檔化。@Documented是一個標記註解,沒有成員。code

@Inherited

@Inherited 是一個標記註解。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個Annotation將被用於該class的子類。

自定義Annotation

在實際項目中,常常會碰到下面這種場景,一個接口的實現類或者抽象類的子類不少,常常須要根據不一樣狀況(好比根據配置文件)實例化並使用不一樣的子類。典型的例子是結合工廠使用職責鏈模式。

此時,能夠爲每一個實現類加上特定的Annotation,並在Annotation中給該類取一個標識符,應用程序可經過該標識符來判斷應該實例化哪一個子類。

下面這個例子,定義了一個名爲Component的Annotation,它包含一個名爲identifier的成員變量。

package com.jasongj.annotation;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Component {
	String identifier () default "";
}

對於上文所說的實現類加上@Component

package com.jasongj;

import com.jasongj.annotation.Component;

@Component(identifier="upper")
public class UpperCaseComponent {

	public String doWork(String input) {
		if(input != null) {
			return input.toUpperCase();
		} else {
			return null;
		}
	}
}

應用程序中能夠經過反射獲取UpperCaseComponent對應的identifier

package com.jasongj;

import com.jasongj.annotation.Component;

public class Client {
    public static void main(String[] args) {
        try {
            Class componentClass = Class.forName("com.jasongj.UpperCaseComponent");
            if(componentClass.isAnnotationPresent(Component.class)) {
                Component component = (Component)componentClass.getAnnotation(Component.class);
                String identifier = component.identifier();
                System.out.println(String.format("Identifier for "
                    + "com.jasongj.UpperCaseComponent is ' %s '", identifier));
            } else {
                System.out.println("com.jasongj.UpperCaseComponent is not annotated by"
						+ " com.jasongj.annotation.Component");
            }
        } catch (ClassNotFoundException ex) {
			ex.printStackTrace();
        }
    }
}

結果以下

Identifier for com.jasongj.UpperCaseComponent is ' upper '

若是把@Component@Retention設置爲 RetentionPolicy.SOURCE或者RetentionPolicy.CLASS,則會獲得以下結果,驗證了上文中對@Retention的描述

com.jasongj.UpperCaseComponent is not annotated by com.jasongj.annotation.Component

Java內置Annotation

Annotation的語法比較簡單,除了@符號的使用外,他基本與Java固有的語法一致,JavaSE中內置三個標準Annotation,定義在java.lang中:

  1. @Override 是一個標記型Annotation,說明了被標註的方法覆蓋了父類的方法,起到了斷言的做用。若是給一個非覆蓋父類方法的方法添加該Annotation,編譯器將報編譯錯誤。它有兩個典型的使用場景,一是在試圖覆蓋父類方法卻寫錯了方法名時報錯,二是刪除已被子類覆蓋(且用Annotation修飾)的父類方法時報錯。
  2. @Deprecated 標記型Annotation,說明被修改的元素已被廢棄並不推薦使用,編譯器會在該元素上加一條橫線以做提示。該修飾具備必定的「傳遞性」:若是咱們經過繼承的方式使用了這個棄用的元素,即便繼承後的元素(類,成員或者方法)並未被標記爲@Deprecated,編譯器仍然會給出提示。
  3. @SuppressWarnnings 用於通知Java編譯器關閉對特定類、方法、成員變量、變量初始化的警告。此種警告通常表明了可能的程序錯誤,例如當咱們使用一個generic collection類而未提供它的類型時,編譯器將提示「unchecked warning」的警告。一般當這種狀況發生時,咱們須要查找引發警告的代碼,若是它真的表示錯誤,咱們就須要糾正它。然而,有時咱們沒法避免這種警告,例如,咱們使用必須和非generic的舊代碼交互的generic collection類時,咱們沒法避免這個unchecked warning,此時能夠在調用的方法前增長@SuppressWarnnings通知編譯器關閉對此方法的警告。

@SuppressWarnnings不是標記型Annotation,它有一個類型爲String[]的成員,這個成員的值爲被禁止的警告名。常見的警告名爲下。

  • unchecked 執行了未檢查的轉換時的警告。例如當使用集合時沒有用泛型來指定集合的類型
  • finally finally子句不能正常完成時的警告
  • fallthrough 當switch程序塊直接通往下一種狀況而沒有break時的警告
  • deprecation 使用了棄用的類或者方法時的警告
  • seriel 在可序列化的類上缺乏serialVersionUID時的警告
  • path 在類路徑、源文件路徑等中有不存在的路徑時的警告
  • all 對以上全部狀況的警告

Annotation與Interface的異同

  • Annotation類型使用關鍵字@interface而非interface。注意開頭的@符號
  • Annotataion的方法定義是受限制的。其方法必須聲明爲無參數、無異常拋出的。這些方法同時也定義了Annotation的成員——方法名即爲成員名,而方法返回類型即爲成員類型。方法返回類型必須爲Java基礎類型、Class類型、枚舉類型、Annotation類型或者相應的一維數組。方法後面可使用default關鍵字和一個默認數值來聲明成員的默認值,null不能做爲成員默認值。成員通常不能是泛型,只有當其類型是Class時可使用泛型,由於此方法可以用類型轉換將各類類型轉換爲Class
  • Annotation和interface均可以定義常量、靜態成員類型,也均可以被實現或者繼承
相關文章
相關標籤/搜索