天天看點

Java 注解詳解 (annotation)

注解是java5的新特性。注解可以看做一種注釋或者中繼資料(metadata),可以把它插入到我們的java代碼中,用來描述我們的java類,進而影響java類的行為。

使用java注解一般來說主要有三種目的

建構時訓示: retentionpolicy.source

編譯期訓示: retentionpolicy.class

運作時訓示: retentionpolicy.runtime

java注解可以用在建構期。當建構我們的工程時,建構程序會編譯源碼、生成xml檔案,打包編譯後的代碼和檔案到jar包。建構過程一般由建構工具自動完成,常用的建構工具有ant、maven。建構工具在建構時會自動掃描我們的代碼,當遇到建構期注解時,會根據注解的内容生成源碼或者其它檔案。

一個java注解由一個@符後面跟一個字元串構成,類似于這樣:

java注解中一般包含一些元素,這些元素類似于屬性或者參數,可以用來設定值,比如我們有一個包含兩個元素的@entity注解:

上面注解中有兩個元素,<code>tablename</code>和<code>primarykey</code>,它們各自都被賦予了自己的元素值。

注解可以用于描述一個類、接口、方法、方法參數、字段、局部變量等。在下邊這個例子中,注解分别用在了類、字段、方法、參數和局部變量中:

java本身提供了三個内置注解,他們分别是:

<code>@deprecated</code>可以用來描述一個類、方法或者字段,表示java不贊成使用這些被描述的對象,如果我們使用了這些類、方法或者字段,編譯器會給我們警告。<code>@deprecated</code>注解使用方法如下:

在我們實際應用中,在使用<code>@deprecated</code>注解時,最好同時使用java doc的<code>@deprecated</code>符号,用來描述目前類、方法或者字段是不贊成使用的,并且告訴開發者應該用哪個對象替換,如下面例子:

<code>@override</code>注解是一個編譯時注解,它主要用在一個子類的方法中,當被注解的子類的方法在父類中找不到與之比對的方法時,編譯器會報錯。 當我們在子類中覆寫父類的方法時,就要用到<code>@override</code>注解,這樣,如果父類中的方法名稱或參數發生改變時,如果子類沒有做相應的調整編譯器便會報錯,這就是<code>@override</code>注解所起到的作用。當然<code>@override</code>注解不是強制使用的,但我還是推薦大家盡量使用它。下面是一個@override注解的例子:

<code>@suppresswarnings</code>注解的作用是使編譯器忽略掉編譯器警告。比如,如果我們的一個方法調用了一個<code>@deprecated</code>方法,或者做了一個不安全的類型轉換,此時編譯器會生成一個警告。如果我們不想看到這些警告,我們就可以使用<code>@suppresswarnings</code>注解忽略掉這些警告:

從上面内置注解可以看到,注解很友善也很有用,很多時候我們也需要建立我們自己的注解。建立注解其實和建立類或接口一樣簡單:

上面代碼便建立了一個<code>@myapplication</code>注解,它一共有四個元素。<code>@interface</code>關鍵字就代表這是一個注解類型,是以使用<code>@interface</code>關鍵字就可以建立注解了。

需要注意的是,注解中的每個元素定義類似于接口中的方法定義。每個元素定義包含一個資料類型和名稱,注解元素的資料類型可以是java基本資料類型、string、數組,但不能是複雜對象類型。

下面這段代碼示範了如何使用注解:

我們可以通過<code>default</code>關鍵字為某個元素設定預設值,當一個元素被設定預設值之後,這個元素便成了注解的可選元素。

下面我們為<code>@myannotation</code>注解的<code>value</code>元素設定一個預設值:

當<code>value</code>元素設定預設值之後,再使用時我們就可以省略掉<code>value</code>元素,此時的<code>value</code>值采用的是預設值:

元注解就是注解的注解。我們可以通過元注解來控制描述我們自定義注解的行為。

<code>@retention</code>用來定義目前注解的作用範圍,如果我們要把我們的自定義注解限制為運作時有效,那麼我們可以使用<code>@retention</code>注解進行指定:

注意<code>@myannotation</code>注解上面的<code>@retention</code>的值:

上面這個注解會告訴編譯器和jvm,這個注解需要在運作時有效,jvm會在運作時通過反射機制擷取注解資訊,關于如何在運作時利用反射擷取注解資訊,最後面會進行介紹。<code>@retention</code>注解的值一共有三種:

retentionpolicy.source : 注解隻存在于源碼中,不會存在于.class檔案中,在編譯時會被忽略掉

retentionpolicy.class:注解隻存在于.class檔案中,在編譯期有效,但是在運作期會被忽略掉,這也是預設範圍

retentionpolicy.runtime:在運作期有效,jvm在運作期通過反射獲得注解資訊

<code>@target</code>注解用來限制自定義注解可以注解java的哪些元素。比如下面這個例子:

這個例子中,<code>@target</code>的值是<code>elementtype.method</code>,通過它的名稱可以看出,這個自定義注解隻能注解類的方法。

<code>elementtype</code>的值一共有以下幾種:

elementtype.annotation_type

elementtype.constructor

elementtype.field

elementtype.local_variable

elementtype.method

elementtype.package

elementtype.parameter

elementtype.type

其中大部分通過名字就能看出它的作用,不過有兩個需要單獨介紹一下:

elementtype.annotation_type:元注解類型,隻能用來注解其它的注解,例如@target和@retention。

elementtype.type:可以用來注解任何類型的java類,如類、接口、枚舉、或者注解類。

<code>@inherited</code>注解表示目前注解會被注解類的子類繼承。比如有一個自定義注解:

如果有一個類使用了上面這個注解:

那麼這個類的子類也會繼承這個注解:

因為<code>mysubclass</code> 繼承了<code>myclass</code>,而<code>myclass</code>的注解<code>@myannotation</code>是可繼承的,最終<code>mysubclass</code>也會有<code>@myannotation</code>注解。

<code>@documented</code>的作用是告訴javadoc工具,目前注解本身也要顯示在java doc中。比如我們用<code>@document</code>注解了我們的自定義注解:

如果一個類使用了這個注解:

那麼當生成<code>mysuperclass</code>的javadoc的時候,<code>@myannotation</code>也會出現在javadoc當中。

上面對注解做了一個詳細介紹,具體該如何使用我們的自定義注解呢?其實在現實應用中,我們的自定義注解一般都是起到運作時訓示的作用,也就是運作時注解。對于運作時注解,我們可以通過反射機制獲得注解資訊。

比如我們有一個自定義注解:

并用這個注解注解了一個類: