下面來看看Java中註解是如何實現的java
建立註解類Inter:函數
建立測試類Test:測試
在程序第二句設置斷點,能夠看到:3d
能夠看到,註解的實例是一個動態代理類的對象.代理
要想查看這個動態代理類,能夠在代碼中加調試
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
添加系統代理,將其導出爲class文件對象
能夠看到以下兩個文件:blog
反編譯$Proxy1.class,以下:繼承
能夠看到,動態代理類是咱們定義的註解實現類,反編譯Inner.class,以下:索引
能夠看到,註解接口繼承了java.lang.annotation.Annotation, 經過查看源碼,該類源碼以下:
能夠看到, 該類下的方法都被$Proxy1動態代理類實現了.
到此處,咱們已經知道Inner註解(接口)是一個繼承了Annotation接口的特殊接口,而咱們經過反射獲取註解時,返回的是Java運行時生成的動態代理對象$Proxy1,該類就是Inner註解(接口)的具體實現類。
那麼, 代理類是如何處理方法的調用的呢?
咱們知道, 動態代理方法的調用最終會傳遞給綁定的InvocationHandler實例的invoke方法處理。咱們能夠看看$Proxy1的源碼
其中語句調用了父類的成員變量,其父類爲Proxy, 查看該成員變量,以下:
能夠看到, h對象類型就是InvocationHandler接口的某個實現類
咱們在Proxy類的構造方法處設置斷點:
經過斷點能夠查看h具體是哪一個對象:
能夠看到, 該動態代理類爲AnnotationInvocationHandler對象, 查看該類的invoke方法以下:
其中的memberValues變量是以方法名爲key,以變量爲value的, 以下:
那麼,這個memberValues變量是從哪來的呢?
能夠看到,其是在構造函數中進行設置的.
反編譯咱們的Test類,看到:
因此中間有一個類,負責建立代理對象AnnotationInvocationHandler, 其將變量從常量池中取出並建立map, 進而建立代理對象, 這個類就是 AnnotationParser, 在此不細說了, 感興趣的能夠自行斷點調試查看.
註解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。經過代理對象調用自定義註解(接口)的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。