http://www.importnew.com/23564.html
1.能夠讀懂别人寫的代碼,特别是架構相關的代碼。
2.本來可能需要很多配置檔案,需要很多邏輯才能實作的内容,就可以使用一個或者多個注解來替代,這樣就使得程式設計更加簡潔,代碼更加清晰。
3.(重點)刮目相看。
(但是怎麼樣才能讓别人刮目相看呢?會用注解不是目的,最重要的是要使用自定義注解來解決問題。)
舉個栗子:
如果面試的時候,你跟老闆說你會使用注解,老闆覺得你這個人還行;但是如果老闆發現你會自定義注解解決問題,老闆肯定就會眼前一亮。
注解這一概念是在java1.5版本提出的,說Java提供了一種原程式中的元素關聯任何資訊和任何中繼資料的途徑的方法。
一、Java中的常見注解
1)JDK注解
JDK注解一共分為三類:

JDK注解.png
案例:
我們先建立一個接口people,如下:
<col>
1
2
3
4
5
<code>public</code> <code>interface</code> <code>people {</code>
<code>public</code> <code>String name();</code>
<code>public</code> <code>int</code> <code>age();</code>
<code>public</code> <code>void</code> <code>work();</code>
<code>}</code>
然後再建一個類Child實作類people這個接口,并實作該類的方法:
6
7
8
9
10
11
12
13
14
15
<code>public</code> <code>class</code> <code>Child </code><code>implements</code> <code>people {</code>
<code>@Override</code>
<code>public</code> <code>String name() {</code>
<code>return</code> <code>null</code><code>;</code>
<code>public</code> <code>int</code> <code>age() {</code>
<code>return</code> <code>0</code><code>;</code>
<code>public</code> <code>void</code> <code>work() {</code>
看到這裡,我們發現這裡的所有方法都會加上一個@Override标記,它告訴我們,同時也告訴編譯器我們的這些方法肯定覆寫了類people裡面的方法的。假如說,我現在把類people裡面的某一個方法注釋掉:
<code>//public String name();</code>
再看類Child裡面的name方法就會報錯。這樣,以後大家看到@Override的時候就能想到這個方法是覆寫了某個接口的方法的。
然後,我們回過頭來看類people裡面有一個work的方法。這裡我們可以了解為人是要工作的,但是并不是所有的人都在工作,那麼怎麼辦呢?如果說這個接口正在用,我們不能删除這個方法,這個時候我們就可以這樣:
<code>@Deprecated</code>
@Deprecated标記就表明這個方法已經過時了,在實際中,它又有什麼樣的應用場景呢?我們在建一個測試類:
<code>public</code> <code>class</code> <code>Test {</code>
<code>people people=</code><code>new</code> <code>Child();</code>
<code>! people.work();</code>
這個時候我們會發現myeclipse會給一個警告,并且在work中間出現一個破折号,意思就是這個方法已經過時了。那麼問題來了,雖然這個方法過時了,但是我們就是那麼傲嬌,一定要用它,怎麼辦呢?隻需要這樣:
<code>@SuppressWarnings</code><code>(</code><code>"deprecation"</code><code>)</code>
<code>people.work();</code>
這樣我們就忽略了這個警告。@SuppressWarnings(“deprecation”)就表示我們忽略了deprecation這樣的一個警告。
2)Java第三方注解
第三方注解.png
二、注解的分類
1)按照運作機制劃分:
【源碼注解→編譯時注解→運作時注解】
源碼注解:隻在源碼中存在,編譯成.class檔案就不存在了。
編譯時注解:在源碼和.class檔案中都存在。像前面的@Override、@Deprecated、@SuppressWarnings,他們都屬于編譯時注解。
運作時注解:在運作階段還起作用,甚至會影響運作邏輯的注解。像@Autowired自動注入的這樣一種注解就屬于運作時注解,它會在程式運作的時候把你的成員變量自動的注入進來。
2)按照來源劃分:
【來自JDK的注解——來自第三方的注解——自定義注解】
3)元注解:
元注解是給注解進行注解,可以了解為注解的注解就是元注解。
三、自定義注解
我們分四步來解析自定義注解:
自定義注解的文法要求:
<code>@Target</code><code>({ElementType.METHOD,ElementType.TYPE})</code>
<code>@Retention</code><code>(RetentionPolicy.RUNTIME)</code>
<code>@Inherited</code>
<code>@Documented</code>
<code>public</code> <code>@interface</code> <code>Description {</code>
<code>String desc();</code>
<code>String author();</code>
<code>int</code> <code>age() </code><code>default</code> <code>18</code><code>;</code>
首先我們要明确這不是一個接口,它是使用@interface關鍵字定義的一個注解。
然後我們看下面的幾個方法,<code>String desc();</code>雖然它很類似于接口裡面的方法,其實它在注解裡面隻是一個成員變量(成員以無參無異常的方式聲明),<code>int age() default 18;</code>(成員變量可以用default指定一個預設值的)。
最後我們要知道:
①.成員類型是受限制的,合法的類型包括基本的資料類型以及String,Class,Annotation,Enumeration等。
②.如果注解隻有一個成員,則成員名必須取名為value(),在使用時可以忽略成員名和指派号(=)。
③.注解類可以沒有成員,沒有成員的注解稱為辨別注解。
元注解:
有沒有發現上面那段代碼有一個沒有說呢?沒錯,它們就是我們所說的元注解:
我們先看第一行:@Target是這個注解的作用域,<code>ElementType.METHOD</code>是這個注解的作用域的清單,<code>METHOD</code>是方法聲明,除此之外,還有:
<code>CONSTRUCTOR(構造方法聲明),FIELD(字段聲明),LOCAL VARIABLE(局部變量聲明),METHOD(方法聲明),PACKAGE(包聲明),PARAMETER(參數聲明),TYPE(類接口)</code>
第二行:@Retention是它的生命周期,前面不是說注解按照運作機制有一個分類嘛,<code>RUNTIME</code>就是在運作時存在,可以通過反射讀取。除此之外,還有:
<code>SOURCE(隻在源碼顯示,編譯時丢棄),CLASS(編譯時記錄到class中,運作時忽略),RUNTIME(運作時存在,可以通過反射讀取)</code>
第三行:@Inherited是一個辨別性的元注解,它允許子注解繼承它。
第四行:@Documented,生成javadoc時會包含注解。
使用自定義注解:
使用注解的文法:
@<注解名>(<成員名1>=<成員值1>,<成員名1>=<成員值1>,…)
<code>@Description</code><code>(desc=</code><code>"i am Color"</code><code>,author=</code><code>"boy"</code><code>,age=</code><code>18</code><code>)</code>
<code>public</code> <code>String Color() {</code>
<code>return</code> <code>"red"</code><code>;</code>
這裡的Description是我們剛才在自定義注解文法要求裡面定義的注解噢,然後我們可以給它的每一個成員變量指派,注意資料類型。值得注意的是,因為我們前面定義的作用域是在方法和類接口上,是以這個注解在Color()方法上使用是沒問題的。
解析注解
概念:
通過反射擷取類 、函數或成員上的運作時注解資訊,進而實作動态控制程式運作的邏輯。
Description類.png
Child類.png
接下來,我們就開始測試了:
16
17
18
<code>public</code> <code>class</code> <code>ParseAnn {</code>
<code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code>try</code> <code>{</code>
<code>// 使用類加載器加載類</code>
<code>Class c = Class.forName(</code><code>"com.test.Child"</code><code>);</code>
<code>// 找到類上面的注解</code>
<code>boolean</code> <code>isExist = c.isAnnotationPresent(Description.</code><code>class</code><code>);</code>
<code>// 上面的這個方法是用這個類來判斷這個類是否存在Description這樣的一個注解</code>
<code>if</code> <code>(isExist) {</code>
<code>// 拿到注解執行個體,解析類上面的注解</code>
<code>Description d = (Description) c.getAnnotation(Description.</code><code>class</code><code>);</code>
<code>System.out.println(d.value());</code>
<code>} </code><code>catch</code> <code>(ClassNotFoundException e) {</code>
<code>e.printStackTrace();</code>
輸出的結果:
<code>i am class annotation</code>
可以看到,我們成功的解析了Child類上面的注解。
接下來,我們繼續解析方法上的注解:
<code>//擷取所有的方法</code>
<code>Method[] ms = c.getMethods();</code>
<code>// 周遊所有的方法</code>
<code>for</code> <code>(Method m : ms) {</code>
<code>boolean</code> <code>isExist1 = m.isAnnotationPresent(Description.</code><code>class</code><code>);</code>
<code>if</code> <code>(isExist1) {</code>
<code>Description d1=m.getAnnotation(Description.</code><code>class</code><code>);</code>
<code>System.out.println(d1.value());</code>
<code>i am method annotation</code>
可以看到,我們成功的解析了方法上面的注解。
<code>//另一種解析方法</code>
<code>//拿到方法上的所有的注解</code>
<code>Annotation[] as=m.getAnnotations();</code>
<code>for</code> <code>(Annotation a : as) {</code>
<code>//用二進制操作符判斷a是否是Description的執行個體</code>
<code>if</code> <code>(a </code><code>instanceof</code> <code>Description) {</code>
<code>Description d=(Description) a;</code>
也可以得到上面的效果。
此時,如果把Description類裡面的元注解改一下,比如:
@Retention(RetentionPolicy.RUNTIME)→@Retention(RetentionPolicy.SOURCE),再運作程式,結果會成怎樣呢?如果改成CLASS呢?讀者們要不要試一試?