Java註解使用及原理解析
基本特性
1、jdk 1.5之後才引入的。
2、用來說明程式的。(註釋是給程式設計師看的,註解就是給電腦看的)
java註解的作用分類
1、編寫文件:通過程式碼標識的註解生成文件。【生成doc文件】
2、程式碼分析:通過程式碼標識的註解對程式碼進行分析。【使用反射】
3、編譯檢查:通過程式碼標識的註解讓編譯器能夠實現基本的編譯檢查。【override】
測試類:
/** * 我的javadoc測試 */ public class TestCode { /** * 計算兩個數的和 * @param a 整數a * @param b 整數b * @return 返回兩個數的和 */ public int add(int a,int b){ return a+b; } }
對於2、3兩點我們應該是知道的。儘管可能不知道里面的原理。但是是平時都在用的。但是對於1點還可以生成doc文件?
測試操作如下:
D:\soft\jdk\bin\javadoc.exe .\TestCode.java -encoding utf-8 -docEncoding utf-8 -charset utf-8
生成了一大堆的東西:
開啟TestCode.html可以發現,我們的java api手冊就是這樣生產的。
註解來源分類
1、jdk自帶的註解,如常見的override(重寫校驗),deprecated(表示棄用)
2、自定義的註解
1)格式,以override為例:
2)註解的本質
我們編寫一個簡單的註解
MyAnnotation.java
public @interface MyAnnotation {}
我們通過編譯和反編譯看下最終是什麼樣的結果:
D:\soft\jdk\bin\javac.exe MyAnnotation.java
D:\soft\jdk\bin\javap.exe MyAnnotation.class
結果如下:
public interface MyAnnotation extends java.lang.annotation.Annotation {
}
可以發現註解的本質就是介面,這個介面繼承了jdk裡面的Annotation介面。
3)註解的屬性
由於註解本質為介面,那麼裡面可以定義未實現的方法。這些稱為註解的“屬性”。
屬性的返回型別有(返回值不能為void):
- 基本資料型別
- String
- 列舉
- 註解
- 以及以上四種類型的陣列
例子:
public enum Person { PS; } public @interface Annotation2 { } public @interface MyAnnotation { String stringValue(); int integerValue(); Person personValue(); Annotation2 myAnnotationValue(); String[] stringArrayValue(); }
屬性的使用,需要注意幾點:
- 定義了屬性在使用的時候就要給屬性賦值,除非設定default值。如:String stringValue() default "aaa";
- 如果屬性為value且屬性只有這一個,那麼value可以省略,直接填寫屬性值。
- 如果是陣列,需要用{}包含起來。
public @interface MyAnnotation { String stringValue() default "xxx"; int integerValue(); String[] stringArrayValue(); } public @interface Annotation2 { String value(); } @MyAnnotation(integerValue = 1,stringArrayValue = {"aaa","bbb"}) @Annotation2("default") public class TestCode { /** * 計算兩個數的和 * @param a 整數a * @param b 整數b * @return 返回兩個數的和 */ public int add(int a,int b){ return a+b; } @Override public String toString() { return super.toString(); } }
元註解
元註解是你在編寫註解的時候,上面加的註解,就是註解的註解。主要有4個。
- @target,用於指定註解的使用位置。如@Target(ElementType.ANNOTATION_TYPE),@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})。
- @Inherited,表示父類加了這個註解,子類也自動加上。
- @Documented,表示這個註解的資訊在執行javadoc的時候是否抽取到api文件中。
- @Retention,表示註解被保留的階段,java類,class檔案,以及被jvm讀取。總共三種。RetentionPolicy.SOURCE,RetentionPolicy.CLASS,RetentionPolicy.RUNTIME
元註解的內容,可以到jdk原始碼裡面看一下,更有利於理解。
解析註解
這個是最關鍵了,以上加了這麼多的屬性,並且還為這些屬性附了值,那麼是希望程式讀取這些值,進行使用的。那其實就是要看如何拿到這些註解配置的值。
測試:
MyAnnotition.java:
package annotation_; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String stringValue() default "xxx"; int integerValue(); }
TestCode.java:
package annotation_; @MyAnnotation(integerValue = 1) public class TestCode { public static void main(String[] args) { Class<TestCode> testCodeClass = TestCode.class; MyAnnotation myAnnotation = testCodeClass.getAnnotation(MyAnnotation.class); int i = myAnnotation.integerValue(); String s = myAnnotation.stringValue(); System.out.printf("i = %d,s = %s\n",i,s); } }
輸出結果:
Connected to the target VM,address: '127.0.0.1:49586',transport: 'socket'
i = 1,s = xxx
Disconnected from the target VM,transport: 'socket'Process finished with exit code 0
是不是感覺可以當配置檔案使用。但是最主要的問題是myAnnotation.integerValue(),myAnnotation.stringValue()為什麼可以拿到對應的值,這個也是最核心的問題。
那就是getAnnotation裡面返回了一個實現了MyAnnotation註解(註解的本質是介面)的例項。這個類大概是長這樣的。
package annotation_; import java.lang.annotation.Annotation; public class MyAnnotationImpl implements MyAnnotation{ public String stringValue() { return "xxx"; } public int integerValue() { return 0; } public Class<? extends Annotation> annotationType() { return null; } }
所以就可以通過抽象方法獲取到對應的值。(如何生成這樣的一個類,只是學習註解,可以不關心。要不然,只能看裡面的原始碼。因為如果自定義註解,你只會用到這一步,去獲取值。)
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。