注解
一、什么是 Annotation? (注解 or 注釋)
Annotation, 準確的翻譯應該是 -- 注解。 和注釋的作用完全不一樣。
Annotation 是JDK5.0及以后版本引入的一個特性。 與類、接口、枚舉是在同一個層次,可以成為java 的一個類型。
語法是以@ 開頭
簡單來說,
注釋是程序員對源代碼的類,方法,屬性等做的一些記憶或提示性描述(比如這個方法是做什么用的),是給人來看的。
注解則是Java 編譯器可以理解的部分,是給編譯器看的。
舉個簡單的例子來看一下注解的使用和作用。
@Override 是比較常見的Java 內置注解,它的作用就是在編譯代碼的時候檢查子類中定義的方法是否正確。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package annotation; public abstract class Animal { public abstract void eat(); } package annotation; public class Cat extends Animal{ @Override public void eat(String food) { } } |
這里在子類Cat中 eat 方法被注解為覆寫父類的方法, 但是卻比父類方法多出一個參數。
如果是在Eclipse 在編輯的話, 直接就會有紅色叉叉提示。(代碼編譯會通不過)。
如果去掉@Override的注解的話, 編譯沒問題, 但是Cat 中eat方法就是這個類的一個新的方法了,而不是從父類繼承的了。
二、常見的Java 內置注解
包含@Override , 還有哪些常見的Java內置注解?
1. @Deprecated
注解為不建議使用,可以用在 方法和類上。
基本上這種方法和類都是因為升級或性能上面的一些原因廢棄不建議使用,但是為了兼容或其他原因,還必須保留。
所以就打上這個注解。
在Java 本身的API中就有很多這樣的例子, 方法打上了這個注解,進到Source code 會看到替代的新的方法是哪個。
在eclipse 中編寫code時,添加此注解的方法在聲明和調用的地方都會加上刪除線。
2.@Override
3.@SuppressWarnings
忽略警告。
如果你的code在轉型或其他的部分有一些警告的話,但是你又想忽略這些警告,就可以使用這個注解了。
1)deprecation 使用了不贊成使用的類或方法時的警告
2)unchecked 執行了未檢查的轉換時警告
3)fallthrough 當使用switch操作時case后未加入break操作,而導致程序繼續執行其他case語句時出現的警告
4)path 當設置一個錯誤的類路徑、源文件路徑時出現的警告
5)serial 當在可序列化的類上缺少serialVersionUID定義時的警告
6)fianally 任何finally子句不能正常完成時警告
7)all 關于以上所有情況的警告
三、自定義注解
除了Java本身提供的內置注解, Java 還提供了定制自定義注解的功能。
定義的方式就是使用注解定義注解, 用來定義注解的注解稱為元注解。
主要的元注解有以下四個:@Target ;@Retention;@Documented;@Inherited
1. @Target 表示該注解用于什么地方,使用在類上,方法上,或是屬性等
可能的 ElemenetType 參數包括:
ElemenetType.CONSTRUCTOR 構造器聲明
ElemenetType.FIELD 域聲明(包括 enum 實例)
ElemenetType.LOCAL_VARIABLE 局部變量聲明
ElemenetType.METHOD 方法聲明
ElemenetType.PACKAGE 包聲明
ElemenetType.PARAMETER 參數聲明
ElemenetType.TYPE 類,接口(包括注解類型)或enum聲明
2. @Retention 表示在什么級別保存該注解信息
可選的 RetentionPolicy 參數包括:
RetentionPolicy.SOURCE 注解將被編譯器丟棄
RetentionPolicy.CLASS 注解在class文件中可用,但會被VM丟棄
RetentionPolicy.RUNTIME VM將在運行期也保留注釋,因此可以通過反射機制讀取注解的信息。
3. @Documented ,產生doc時,是否包含此注解
將此注解包含在 javadoc 中
4. @Inherited
允許子類繼承父類中的注解
看一些簡單定義的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (ElementType.METHOD) public @interface MyAnnotation { String value(); } @Retention (RetentionPolicy.SOURCE) @interface MyAnnotation1 { } @Retention (RetentionPolicy.CLASS) @interface MyAnnotation2 {} @Retention (RetentionPolicy.RUNTIME) @interface MyAnnotation3 {} @Documented @interface MyAnnotation4 {} @Inherited @interface MyAnnotation5 { } |
四、使用例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package annotation; import java.lang.annotation.Annotation; @MyAnnotation3 public class TestAnnotation { public static void main(String[] args) { // TODO Auto-generated method stub Annotation annotation = TestAnnotation. class .getAnnotation(MyAnnotation3. class ); System.out.println(annotation.toString()); } } |
打印出結果: @annotation.MyAnnotation3()
以上例子如果替換使用 MyAnnotation1 和 MyAnnotation2 的話, 則取到的annotation的值為空,這就是RetentionPolicy 不同的差別。
五、Annotation的作用
介紹到此,可以總結一下Annotation的作用了。
基礎的大致可以分為三類:
1. 編寫文檔
2. 代碼分析
3. 編譯檢查
但是,開源框架對其賦予了更多的作用
比如:
Hibernate,注解配置,
1
2
|
@Column ( "aa" ) private String xx; |
這個類似于XML配置,簡化程序中的配置
相對與把一部分元數據從XML文件移到了代碼本身之中,在一個地方管理和維護。
內部如何實現的? -- java 反射機制,類似與以上例子。
注釋
雖然注解、注釋只相差一個字,但是用法就差異很大。
還是那句話, 注解給編譯器看, 注釋是給人看的。
基于此的話, 對于一個方法來說:
1. 把這個方法的作用, 輸入,輸出描述清楚就可以了,更多的可以加上一些作者呀,版本呀這樣一些信息
2. 注釋編排的美觀一些
做到這兩點應該就可以了。 舉個例子:
1
2
3
4
5
6
7
8
|
/******************************************************************************* * NAME: usage * DESCRIPTION: XXX * ARGUMENTS: N/A * RETURN: * AUTHOR: oscar999 * VERSION: V0.1 *******************************************************************************/ |
看上去這是一個不錯的注釋^^.
但是對于Java 語言來說, 注釋被賦予了更多的功能。 就是你可以使用javadoc 這個功能把代碼中的注釋導出到 html 的文件中。
如果你的代碼是共用性很高的代碼的話, 這份文檔就是一份API的參考文檔, 類似Java API.
所以, 要產生出這樣的文檔,就要遵循java 定義的一些注釋規范, 才能產生出規范的文檔出來。
一、Java 類方法的標準注釋
還是從類的方法的注釋說起。
1
2
3
4
5
6
7
|
/** * Read a line of text. A line is considered to be terminated by any one * of a line feed ('\n'), a carriage return ('\r'), or a carriage return * followed immediately by a linefeed. * * @param ignoreLF1 If true, the next '\n' will be skipped <pre code_snippet_id="74911" snippet_file_name="blog_20131120_2_8365599" name="code" class="java"> * @param ignoreLF2 If true, the next '\n' will be skipped</pre> * * @return A String containing the contents of the line, not including * any line-termination characters, or null if the end of the * stream has been reached * * @see java.io.LineNumberReader#readLine() * * @exception IOException If an I/O error occurs */ |
(不去關注以上注釋的意義,只關注其定義的樣式)
1. 首先看最上面的 “Read a line of text. A line .. ” 這一段是對這個方法的一些描述。
第一個句號前面的部分, 也就是 “Read a line of text.” 會出現在 “方法摘要” 中
2. @param 定義的是方法的輸入參數,(可以添加多個)出現在“ 方法詳細信息” 中。(參數和參數描述之間使用空格隔開, 在產生的文檔中轉成了 -)
3. @return 返回值的描述
4. @see 參考的描述
5. @exception 異常拋出的描述
美觀考慮, 不同類的標簽可以換一行顯示, 比如 @param 和 @return 直接空一行。
二、Java 類標準注釋
類的注釋和方法注釋的格式基本相同。 區別的地方:
1. 放置的位置不同。 類的注釋放在類定義的上面, 方法的注釋放在方法定義的上面。
2. 類的注釋比較會使用 @version @author @since 這樣的標簽。
看模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** will buffer the input from the specified file. Without buffering, each * invocation of read() or readLine() could cause bytes to be read from the * file, converted into characters, and then returned, which can be very * inefficient. * * * Test Description * * <p> Programs that use DataInputStreams for textual input can be localized by * replacing each DataInputStream with an appropriate BufferedReader. * * @see FileReader * @see InputStreamReader * * @version 0.1, 11/20/13 * @author oscar999 * @since JDK1.5 */ |
doc 中顯示的效果是:
同樣, 描述的第一句出現在“類概要”中。
類的詳細信息顯示如下:
值得注意的是 description 中<p> 的使用。 如果沒有加<p> , 在java code 中不管是否有換行,產生的doc 中都不換行。 加上<p> 的話, doc 中出現換行。
三、補充
補充一下, 產生javadoc的方法:
1. 命名行方式: javadoc + 參數
2. 使用Eclipse IDE 導出
如果在Eclipse IDE 中, 在源文件或是項目上右鍵單擊 , 選 Export --->
Java --> Javadoc 就可以產生了。