Java內建的註解以及自定義一個註解大家都比較熟悉的了,現在來看看註解實現的原理,看看Java的體系下面是如何對註解的支援的。
在討論前先看一個自定義註解的例子,自定義實現這樣一個註解:通過@Test向某類注入一個字串,通過@TestMethod向某個方法注入一個字串。
① 建立Test註解,宣告作用於類並保留到執行時,預設值為default。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String value() default "default";
}複製程式碼
② 建立TestMethod註解,宣告作用於方法並保留到執行時。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMethod {
String value();
}複製程式碼
③測試類,執行後輸出default和tomcat-method兩個字串,因為@Test沒有傳入值,所以輸出了預設值,而@TestMethod則輸出了注入的字串。
@Test()
public class AnnotationTest {
@TestMethod("tomcat-method")
public void test(){
}
public static void main(String[] args){
Test t = AnnotationTest.class.getAnnotation(Test.class);
System.out.println(t.value());
TestMethod tm = null;
try {
tm = AnnotationTest.class.getDeclaredMethod("test",null).getAnnotation(TestMethod.class);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(tm.value());
}
}複製程式碼
對於註解Test,如果對AnnotationTest類進行註解,則執行時可以通過AnnotationTest.class.getAnnotation(Test.class)獲取註解宣告的值,從上面的句子就可以看出,它是從class結構中獲取出Test註解的,所以肯定是在某個時候註解被加入到class結構中去了。
@Test("test")
public class AnnotationTest {
public void test(){
}
}複製程式碼
從java原始碼到class位元組碼是由編譯器完成的,編譯器會對java原始碼進行解析並生成class檔案,而註解也是在編譯時由編譯器進行處理,編譯器會對註解符號處理並附加到class結構中,根據jvm規範,class檔案結構是嚴格有序的格式,唯一可以附加資訊到class結構中的方式就是儲存到class結構的attributes屬性中。我們知道對於類、欄位、方法,在class結構中都有自己特定的表結構,而且各自都有自己的屬性,而對於註解,作用的範圍也可以不同,可以作用在類上,也可以作用在欄位或方法上,這時編譯器會對應將註解資訊存放到類、欄位、方法自己的屬性上。
在我們的AnnotationTest類被編譯後,在對應的AnnotationTest.class
檔案中會包含一個RuntimeVisibleAnnotations
屬性,由於這個註解是作用在類上,所以此屬性被新增到類的屬性集上。即Test註解的鍵值對value=test
會被記錄起來。而當JVM載入AnnotationTest.class
檔案位元組碼時,就會將RuntimeVisibleAnnotations屬性值儲存到AnnotationTest的Class物件中,於是就可以通過AnnotationTest.class.getAnnotation(Test.class)
獲取到Test註解物件,進而再通過Test註解物件獲取到Test裡面的屬性值。
這裡可能會有疑問,Test註解物件是什麼?其實註解被編譯後的本質就是一個繼承Annotation介面的介面,所以@Test其實就是public interface Test extends Annotation
,當我們通過AnnotationTest.class.getAnnotation(Test.class)
呼叫時,JDK會通過動態代理生成一個實現了Test介面的物件,並把將RuntimeVisibleAnnotations
屬性值設定進此物件中,此物件即為Test註解物件,通過它的value()方法就可以獲取到註解值。
Java註解實現機制的整個過程如上面所示,它的實現需要編譯器和JVM一起配合。
====廣告時間,可直接跳過====
鄙人的新書《Tomcat核心設計剖析》已經在京東預售了,有需要的朋友可以到 item.jd.com/12185360.ht… 進行預定。感謝各位朋友。
=========================
歡迎關注: