最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

Java ASM詳解:注解

2022-10-26 23:34 作者:Nickid2018  | 我要投稿

在 Java 語言中,注解(Annotation)是很重要的一部分。它的存在讓許多代碼變得簡潔。與注解執(zhí)行器(Annotation Processor)結合之后,它能發(fā)揮出意想不到的功能。這篇文章就將講述注解是什么寫入在字節(jié)碼中的。

注解類型的定義在前文(類的結構二)中已經寫過了,如果不了解注解類型的寫入可以先查看那一篇文章。

一.寫入注解信息

寫入注解信息需要用到 AnnotationVisitor 這個類,它含有的方法支持我們對注解添加信息

1.寫入常量

寫入常量需要使用 visit 方法,它的第一個參數代表注解屬性的名稱,第二個參數代表值。可以寫入的常量類型有:8種基本類型、字符串和 Type 對象(不包括方法描述符)。

2.寫入枚舉常量

寫入枚舉常量需要使用 visitEnum 方法,第一個參數仍然是注解屬性的名稱,第二個是枚舉對象的類型描述符,第三個是枚舉對象的名稱。

3.寫入其他注解類型

寫入其他注解類型對象需要使用 visitAnnotation 方法,第一個參數是注解屬性名稱,第二個是要寫入的注解類型的類型描述符。這個方法返回一個新的 AnnotationVisitor ,使用這個新的 visitor 可以填充要寫入的注解類型對象的信息。

假如說我們要寫入下面的注解:

我們需要寫下面這些代碼:

4.寫入數組

除了上述類型之外,注解類型還允許在注解中定義一維數組。寫入數組需要用到 visitArray
方法,參數為注解屬性名稱,返回一個新的 AnnotationVisitor 用于填充這個數組。寫入數組信息時,所有的注解屬性名稱都要寫為 null,并且不允許再調用 visitArray,因為注解類型不允許二維及多維數組的存在。

下面是一個例子:

寫入需要下面的代碼:

5.寫入帶有@Repeatable注解的注解類型

通常情況下,一個注解位置每個注解類型只能聲明一次,但是帶有 @Repeatable 的注解類型可以多次聲明。假設有下面的注解類型:

如果在注釋位置上只有一個 Test 注解,那么寫入時只需要寫 Test;但是如果一個位置上有多個 Test 注解,則應該使用 TestContainer 進行等效代替并寫入,像下面這樣:

二.注解類型的可見性

根據不同注解類型的作用,在定義注解類型時我們通常都會設置它的可見性,也就是使用 @Retention 進行設置。

RetentionPolicy 枚舉與可見性的關系

可見性影響了反射時我們能不能訪問到這個注解,如果不寫則默認為 false。

三.注解的寫入位置

注解不是哪里都能寫入的,它有一套非常詳細的使用方法,下面我們將分類講解。

1.類和類成員定義時的注解

當類與類的成員(字段、方法、記錄元素)被定義時,它可以附加注解,例如:

這種注解在寫入時需要調用各個 visitor 的 visitAnnotation 方法。其中第一個參數是注解類型的類型描述符,第二個是注解類型的可見性。

對于附加在類 TestAnnotation 上的注解 Retention,我們需要這樣寫入:

如果一個成員在被定義時被添加上了 @Deprecated 注解,那么在定義這個成員時也要加上 ACC_DEPRECATED 訪問標志。

對于 value 方法,我們需要這樣寫入:

2.類型的注解

在類型上,我們也能加入注解,這些注解 @Target 中必須含有 TYPE_USE。要知道類型的注解怎么插入,我們需要先了解兩個概念:類型路徑(Type Path)和類型引用(Type
Reference)。

a.類型路徑

為了指定注解在類型中的位置,JVM 引入了類型路徑。假設我們有下面一個泛型需要進行注解:

可以看到,注解 ABCDE 分別注解了一個復雜類型中的不同元素。如果我們從類型的最外層開始對類型的參數進行遍歷,我們就能最終指定插入的位置。遍歷的每一(step)都含有兩個屬性:

  • 類型路徑類別(Type Path Kind),它決定了這一步該走向哪種元素,可以使用的值如下表:

類型路徑類別
  • 類型參數索引(Type Argument Index),代表在同一級的幾個相同類別的元素中要選擇哪個。例如在 Map<@A Test, Object> 中,泛型參數共有兩個,要指定其中一個需要用到這個索引。請注意,只有泛型參數才需要指定索引,其它的類別不需要。

假設我們有下面的類型需要注解:

那么我們訪問到注解 A 的路徑就像這樣:

對于數組來說,注解的位置影響了它的路徑長度,下面是按照 A 注解類型路徑長度逐漸增大排序的注解示例:

下面是一個組合的例子:

在 ASM 庫中,類型路徑使用 TypePath 包裝,創(chuàng)建一個 TypePath 對象需要使用 fromString 方法,它的參數是一個字符串,這個字符串里面存儲了可以復原 TypePath 的所有信息。對于每一步,都有一個對應關系,這些步按順序連接起來就能復原 TypePath。

類別和字符串的映射關系

上面的例子可以用 0;*.0;[[ 代替。

b.類型引用

類型路徑決定了注解在一個類型內的位置,而類型引用指定了這個被注解類型的位置。

類型引用本質上是一個 int,其中第25~32位是引用的類型,1~24位是引用的參數。ASM 庫提供了 TypeReference 類來簡化創(chuàng)建這些數字的代碼。

先來說說無參的類型引用類型,這些類型可以使用 newTypeReference 創(chuàng)建 TypeReference 對象,之后通過 getValue 方法獲得 int 形式的類型引用,如下表:

無參類型引用

接下來說一下有參的類型引用類型。

  • 需要類型參數的類型引用。它們需要使用 newTypeParameterReference 獲得 TypeReference 對象,第二個參數是類型參數的序號。

需要類型參數的類型引用
  • 需要類型參數邊界的類型引用。類型參數邊界即 <T extends ...> 這種類型參數后面的限定,可以不止一個。它們需要使用 newTypeParameterBoundReference 獲得TypeReference 對象,第二個參數是類型參數的序號,第三個參數是規(guī)定邊界限定的序號。

需要類型參數邊界的類型引用
  • 需要超類序號的類型引用。超類序號是定義類時指定的繼承類和實現(xiàn)類的序號,繼承類的序號是-1,實現(xiàn)類的序號按照定義順序從0計數。使用 newSuperTypeReference 創(chuàng)建 TypeReference 對象,第二個參數就是超類序號。類型固定為 CLASS_EXTENDS,可用在 ClassVisitor::visitTypeAnnotationRecordComponentVisitor::visitTypeAnnotation 方法中。

  • 需要方法形式參數序號的類型引用。使用 newFormalParameterReference 創(chuàng)建對象,類型固定為 METHOD_FORMAL_PARAMETER,可用在 MethodVisitor::visitTypeAnnotation 中。

  • 需要方法異常列表序號的類型引用。使用 newExceptionReference 創(chuàng)建 TypeReference,類型固定為 THROWS,可用在 MethodVisitor::visitTypeAnnotation 中。

  • 需要 try-catch 塊序號的類型引用。用 newTryCatchReference 創(chuàng)建,類型是 EXCEPTION_PARAMETER,使用 MethodVisitor::visitTryCatchAnnotation 寫入字節(jié)碼。

  • 需要實際參數序號的類型引用。它們需要使用 newTypeArgumentReference 創(chuàng)建,都需要使用 MethodVisitor::visitInsnAnnotation 寫入。

需要實際參數序號的類型引用

下面是一個例子:

下面將寫入這個 test 方法:

3.方法形式參數上的注解

等下,我們剛剛不是說過形式參數上怎么插入注解了嗎?事實上,形式參數可以使用兩種注解:一種是標記為 TYPE_USE 的類型注解,另一種是標記為 PARAMETER 的形式參數注解。如果一個注解同時擁有這兩個標志,就都要寫入字節(jié)碼。

寫入形式參數注解需要兩步:寫入注解形式參數數量、寫入形式參數注解。

寫入注解形式參數數量需要使用 visitAnnotableParameterCount 方法。假設我們有一個方法:

它的形式參數是兩個,因為接收器 this 不是形式參數。寫入如下:

第二個參數代表了注解的可見性。

寫入形式參數注解需要使用 visitParameterAnnotation,參數類似定義注解的使用方法。

請注意:如果形式參數列表中同時存在運行時可見和不可見的注解,那么先寫 visitAnnotableParameterCount,可見性為 true,在后面寫出所有運行時可見的注解;之后再一行 visitAnnotableParameterCount,可見性為 false,在后面寫出所有運行時不可見的注解。visitAnnotableParameterCount 對于每個可見性只出現(xiàn)一次。

4.注解類型中的 default 默認值

在類的結構二中,我們說到了有默認值的注解屬性怎么寫入。它使用的是 visitAnnotationDefault 方法。

它返回的 AnnotationVisitor 需要寫入一個 name 為 null 的屬性,這個屬性寫入什么值和怎么寫入取決于你要決定的默認值。

到這里有關于注解的相關知識都已經說完了,下篇專欄可能是 ASM Tree API 部分。


Java ASM詳解:注解的評論 (共 條)

分享到微博請遵守國家法律
项城市| 松桃| 德州市| 平山县| 灵武市| 黑龙江省| 丹凤县| 全州县| 岳池县| 旬邑县| 六枝特区| 兴山县| 东台市| 潞城市| 英吉沙县| 河西区| 绿春县| 荆州市| 抚远县| 葵青区| 梧州市| 泗阳县| 阿拉尔市| 濮阳县| 黄骅市| 正安县| 阜南县| 疏勒县| 固始县| 荃湾区| 黔江区| 鄂托克前旗| 寻甸| 台湾省| 和田市| 苍南县| 靖西县| 灵寿县| 西贡区| 会东县| 白沙|