1. 程式人生 > >[轉帖收集] Java註解

[轉帖收集] Java註解

cto 這一 字段 declare rri 鼓勵 指定 包含成員 容易

1、Annotation


它的作用是修飾編程元素。什麽是編程元素呢?例如:包、類、構造方法、方法、成員變量等。Annotation(註解)就是Java提供了一種元程序中的元素關聯任何信息和任何元數據(metadata)的途徑和方法。Annotion(註解)是一個接口,程序可以通過反射來獲取指定程序元素的Annotion對象,然後通過Annotion對象來獲取註解裏面的元數據。

Annotation(註解)是JDK5.0及以後版本引入的。它可以用於創建文檔,跟蹤代碼中的依賴性,甚至執行基本編譯時檢查。從某些方面看,annotation就像修飾符一樣被使用,並應用於包、類 型、構造方法、方法、成員變量、參數、本地變量的聲明中。這些信息被存儲在Annotation的“name=value”結構對中。

Annotation的成員在Annotation類型中以無參數的方法的形式被聲明。其方法名和返回值定義了該成員的名字和類型。在此有一個特定的默認語法:允許聲明任何Annotation成員的默認值:一個Annotation可以將name=value對作為沒有定義默認值的Annotation成員的值,當然也可以使用name=value對來覆蓋其它成員默認值。這一點有些近似類的繼承特性,父類的構造函數可以作為子類的默認構造函數,但是也可以被子類覆蓋。

  Annotation能被用來為某個程序元素(類、方法、成員變量等)關聯任何的信息。需要註意的是,這裏存在著一個基本的規則:Annotation不能影響程序代碼的執行,無論增加、刪除 Annotation,代碼都始終如一的執行。另外,盡管一些annotation通過java的反射api方法在運行時被訪問,而java語言解釋器在工作時忽略了這些annotation。正是由於java虛擬機忽略了Annotation,導致了annotation類型在代碼中是“不起作用”的; 只有通過某種配套的工具才會對annotation類型中的信息進行訪問和處理。本文中將涵蓋標準的Annotation和meta-annotation類型,陪伴這些annotation類型的工具是java編譯器(當然要以某種特殊的方式處理它們)。

2、什麽是metadata(元數據):


  元數據從metadata一詞譯來,就是“關於數據的數據”的意思。
  元數據的功能作用有很多,比如:你可能用過Javadoc的註釋自動生成文檔。這就是元數據功能的一種。總的來說,元數據可以用來創建文檔,跟蹤代碼的依賴性,執行編譯時格式檢查,代替已有的配置文件。如果要對於元數據的作用進行分類,目前還沒有明確的定義,不過我們可以根據它所起的作用,大致可分為三類:
    1. 編寫文檔:通過代碼裏標識的元數據生成文檔
    2. 代碼分析:通過代碼裏標識的元數據對代碼進行分析
    3. 編譯檢查:通過代碼裏標識的元數據讓編譯器能實現基本的編譯檢查

  在Java中元數據以標簽的形式存在於Java代碼中,元數據標簽的存在並不影響程序代碼的編譯和執行,它只是被用來生成其它的文件或針在運行時知道被運行代碼的描述信息。
  綜上所述:
    第一,元數據以標簽的形式存在於Java代碼中。
    第二,元數據描述的信息是類型安全的,即元數據內部的字段都是有明確類型的。
    第三,元數據需要編譯器之外的工具額外的處理用來生成其它的程序部件。
    第四,元數據可以只存在於Java源代碼級別,也可以存在於編譯之後的Class文件內部。

3、Annotation和Annotation類型:


  Annotation使用了在java5.0所帶來的新語法,它的行為十分類似public、final這樣的修飾符。每個Annotation具有一個名字和成員個數>=0。每個Annotation的成員具有被稱為name=value對的名字和值(就像javabean一樣),name=value裝載了Annotation的信息。

  Annotation類型定義了Annotation的名字、類型、成員默認值。一個Annotation類型可以說是一個特殊的java接口,它的成員變量是受限制的,而聲明Annotation類型時需要使用新語法。當我們通過java反射api訪問Annotation時,返回值將是一個實現了該 annotation類型接口的對象,通過訪問這個對象我們能方便的訪問到其Annotation成員。後面的章節將提到在java5.0的 java.lang包裏包含的3個標準Annotation類型。

4、註解的分類:


  根據註解參數的個數,我們可以將註解分為三類:
    1.標記註解:一個沒有成員定義的Annotation類型被稱為標記註解。這種Annotation類型僅使用自身的存在與否來為我們提供信息。比如後面的系統註解@Override;
    2.單值註解
    3.完整註解  
  根據註解使用方法和用途,我們可以將Annotation分為三類:
    1.JDK內置系統註解
    2.元註解
    3.自定義註解

5、系統內置標準註解:


  註解的語法比較簡單,除了@符號的使用外,他基本與Java固有的語法一致,JavaSE中內置三個標準註解,定義在java.lang中:
    @Override:用於修飾此方法覆蓋了父類的方法; ---起到了斷言的作用。
    @Deprecated:用於修飾已經過時的方法; ---編譯器將不鼓勵使用這個被標註的程序元素。
    @SuppressWarnnings:用於通知java編譯器禁止特定的編譯警告。
-----Deprecated具有一定的 “延續性”:如果我們在代碼中通過繼承或者覆蓋的方式使用了這個過時的類型或者成員,雖然繼承或者覆蓋後的類型或者成員並不是被聲明為 @Deprecated,但編譯器仍然要報警。
----SuppressWarning不是一個標記註解。它有一個類型為String[]的成員,這個成員的值為被禁止的警告名。

SuppressWarnings註解的常見參數值的簡單說明:
    1.deprecation:使用了不贊成使用的類或方法時的警告;
    2.unchecked:執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型;
    3.fallthrough:當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告;
    4.path:在類路徑、源文件路徑等中有不存在的路徑時的警告;
    5.serial:當在可序列化的類上缺少 serialVersionUID 定義時的警告;
    6.finally:任何 finally 子句不能正常完成時的警告;
    7.all:關於以上所有情況的警告。

annotation語法允許在annotation名後跟括號,括號中是使用逗號分割的name=value對用於為annotation的成員賦值。
----@SuppressWarnings(value={ "rawtypes", "unchecked" })

6、自定義註解


1)以@interface關鍵字定義
(2)註解包含成員,成員以無參數的方法的形式被聲明。其方法名和返回值定義了該成員的名字和類型。
(3)成員賦值是通過@Annotation(name=value)的形式。
(4)註解需要標明註解的生命周期,註解的修飾目標等信息,這些信息是通過元註解實現。
上面的語法不容易理解,下面通過例子來說明一下,這個例子就是Target註解的源碼,

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE } )
public @interface Target
{
ElementType[] value();
}
源碼分析如下:
第一:元註解@Retention,成員value的值為RetentionPolicy.RUNTIME。
第二:元註解@Target,成員value是個數組,用{}形式賦值,值為ElementType.ANNOTATION_TYPE
第三:成員名稱為value,類型為ElementType[]
另外,需要註意一下,如果成員名稱是value,在賦值過程中可以簡寫。如果成員類型為數組,但是只賦值一個元素,則也可以簡寫。如上面的簡寫形式為:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)

7、註解的生命周期


註解的定義語法中已經說到了:註解需要標明註解的生命周期,這些信息是通過元註解實現。而這個元註解是:
public @interface Retention
{
RetentionPolicy value();
}
Retention註解的值是enum類型的RetentionPolicy。包括如下幾種情況:
(1)SOURCE: 註解只保留在源文件,當Java文件編譯成class文件的時候,註解被遺棄。Annotations are to be discarded by the compiler.
(2)CLASS: 註解被保留到class文件,jvm加載class文件時候被遺棄。這是默認的生命周期。
Annotations are to be recorded in the class file by the compiler,
but need not be retained by the VM at run time. This is the default behavior.
(3)RUNTIME: 註解不僅被保存到class文件中,jvm加載class文件之後,仍然存在,保存到class對象中,可以通過反射來獲取。
Annotations are to be recorded in the class file by the compiler and
retained by the VM at run time, so they may be read reflectively.

8、註解的修飾目標


註解的定義語法中已經說到了:註解需要標明註解的修飾目標,這些信息是通過元註解實現。而這個元註解是:
public @interface Target
{
ElementType[] value();
}
這個註解的值是enum類型ElementType。包括以下幾種情況:
(1)TYPE:指的是在類,接口(包括註解)或者enum上使用的註解。
(2)FIELD:指的在field屬性,也包括enum常量使用的註解。
(3)METHOD:指的是在方法聲明上使用的註解。
(4)PARAMETER:指的是在參數上使用的註解,
(5)CONSTRUCTOR: 指的是在構造器使用的註解。
(6)LOCAL_VARIABLE:指的是在局部變量上使用的註解。
(7)ANNOTATION_TYPE:指的是在註解上使用的元註解
(8)PACKAGE:指的是在包上使用的註解。

9、註解的底層實現


定義一個註解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Cache
{
String value() default "cache";
}
用javap -verbose 分析其字節碼,如下圖所示:
技術分享
分析上面的字節碼,我們可以得出:
第一:public interface Cache extends java.lang.annotation.Annotation,說明Cache註解是繼承自Annotation,仍然是interface。
第二:public abstract java.lang.String value(),說明value方法是abstract類型。

10、註解的繼承


@Inherited 用於描述Annotation可以被繼承
如果一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
註意:@Inherited annotation類型是被標註過的class的子類所繼承。不從接口繼承annotation,方法並不從重載的方法繼承annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AnnonitionTargetTest {
}

11、註解處理器類

接口 java.lang.reflect.AnnotatedElement,它的實現類:

java.lang.Class類,
java.lang.reflect.Filed類,
java.lang.reflect.Constructor類,
java.lang.reflect.Method類,
java.lang.Package類
相關方法:
<T extends Annotation> T getAnnotation(Class<T> annotationClass); 返回該程序元素上存在的、指定類型的註解,如果該類型註解不存在,則返回null。
Annotation[] getAnnotations(); 返回該程序元素上存在的所有註解。
boolean isAnnotationPresent(Class<T extends Annotation> annotationClass); 判斷該程序元素上是否包含指定類型的註解,存在則返回true,否則返回false.
Annotation[] getDeclaredAnnotations(); 返回直接存在於此元素上的所有註解。與此接口中的其他方法不同,該方法將忽略繼承的註釋。(如果沒有註釋直接存在於此元素上,則返回長度為零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ps: 內容來自以下博文,侵刪。

http://www.cnblogs.com/peida/archive/2013/04/23/3036035.html

http://swiftlet.net/archives/1906

http://www.cnblogs.com/imeng/p/4023125.html

[轉帖收集] Java註解