天天看點

注解的原理

前面介紹了如何使用Java内置的注解以及如何自定義一個注解,接下去看看注解實作的原理,看看在Java的大體系下面是如何對注解的支援的。還是回到上面自定義注解的例子,對于注解Test,如下,如果對AnnotationTest類進行注解,則運作時可以通過<code>AnnotationTest.class.getAnnotation(Test.class)</code>擷取注解聲明的值,從上面的句子就可以看出,它是從class結構中擷取出Test注解的,是以肯定是在某個時候注解被加入到class結構中去了。

<code>@Test("test") public class AnnotationTest { public void test(){ } }</code>

從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其實就是<code>“public interface Test extends Annotation”</code>,當我們通過<code>AnnotationTest.class.getAnnotation(Test.class)</code>調用時,JDK會通過動态代理生成一個實作了Test接口的對象,并把将RuntimeVisibleAnnotations屬性值設定進此對象中,此對象即為Test注解對象,通過它的value()方法就可以擷取到注解值。

Java注解實作機制的整個過程如上面所示,它的實作需要編譯器和JVM一起配合。

========廣告時間========

<a href="http://blog.csdn.net/wangyangzhizhou/article/details/74080321">為什麼寫《Tomcat核心設計剖析》</a>

=========================

歡迎關注:

注解的原理