1. 程式人生 > >Java註解的基本原理

Java註解的基本原理

註解的本質就是一個繼承了Annotation介面的介面,一個註解準確意義上來說,只不過是一種特殊註釋而已,如果沒有解析他的程式碼,他可能連註釋都不如。
 解析一個類或者方法的註解往往有兩種形式,一種是編譯期直接的掃描,一種是執行期反射。

Java中有以下幾個元註解

@Target: 註解的作用目標
@Retention: 註解的生命週期
@Documented: 註解是否應當被包含在javaDoc文件中
@Inherited: 是否允許子類繼承該註解

1)@Target中作用範圍對應的列舉值:

ElementType.TYPE:允許被修飾的註解作用在類、介面和列舉上
ElementType.FIELD:允許作用在屬性欄位上
ElementType.METHOD:允許作用在方法上
ElementType.PARAMETER:允許作用在方法引數上
ElementType.CONSTRUCTOR:允許作用在構造器上
ElementType.LOCAL_VARIABLE:允許作用在本地區域性變數上
ElementType.ANNOTATION_TYPE:允許作用在註解上
ElementType.PACKAGE:允許作用在包上

2)@RetentionPolicyd取值對應列舉:
RetentionPolicy.SOURCE:當前註解編譯期可見,不會寫入 class 檔案
RetentionPolicy.CLASS:類載入階段丟棄,會寫入 class 檔案
RetentionPolicy.RUNTIME:永久儲存,可以反射獲取
3)@Inherited 註解修飾的註解是具有可繼承性的,也就說我們的註解修飾了一個類,而該類的子類將自動繼承父類的該註解
註解和反射
虛擬機器規範定義了一系列和註解相關的屬性表,也就是說,無論是欄位、方法或者是類本身,如果被註解修飾了,就可以被寫進位元組碼檔案,屬性表有以下幾種:
RuntimeVisibleAnnotations:執行時可見的註解
RuntimeInVisibleAnnotations:執行時不可見的註解
RuntimeVisibleParameterAnnotations:執行時可見的方法引數註解
RuntimeInVisibleParameterAnnotations:執行時不可見的方法引數註解
AnnotationDefault:註解類元素的預設值
所以,對於一個類或者介面來說,Class類中提供以下一些方法用於反射註解
getAnnotation:返回指定的註解
isAnnotationPresent:判定當前元素是否被指定註解修飾
getAnnotations:返回所有的註解
getDeclaredAnnotation:返回本元素的指定註解
getDeclaredAnnotations:返回本元素的所有註解,不包含父類繼承而來的

總結
首先,我們通過鍵值對的形式可以為註解屬性賦值。
接著,你用註解修飾某個元素,編譯器將在編譯期掃描每個類或者方法上的註解,會做一個基本的檢查,你的這個註解是否允許作用在當前位置,最後會將註解資訊寫入元素的屬性表。
然後,當你進行反射的時候,虛擬機器將所有生命週期在 RUNTIME 的註解取出來放到一個 map 中,並建立一個 AnnotationInvocationHandler 例項,把這個 map 傳遞給它。
最後,虛擬機器將採用 JDK 動態代理機制生成一個目標註解的代理類,並初始化好處理器。
那麼這樣,一個註解的例項就創建出來了,它本質上就是一個代理類,你應當去理解好 AnnotationInvocationHandler 中 invoke 方法的實現邏輯,這是核心。
一句話概括就是,通過方法名返回註解屬性值