1. 概要

注釈、Javaコードに追加できるメタデータの形式。 これらは 注釈 コンパイル時に処理してクラスファイルに埋め込むか、実行時に保持してアクセスすることができます。 反射.

この記事では、変更方法について説明します 注釈 Reflectionを使用した実行時の値。 この例では、クラスレベルのアノテーションを使用します。

2. 注釈

Javaでは、既存の注釈を使用して新しい注釈を作成できます。 最も単純な形式では、注釈は@記号の後に注釈名が続くものとして表されます。

@Override

独自の注釈Greeterを作成しましょう。

@Retention(RetentionPolicy.RUNTIME)
public @interface Greeter {    
    public String greet() default ""; 
}

次に、Javaクラスを作成します ご挨拶 クラスレベルを使用します 注釈:

@Greeter(greet="Good morning")
public class Greetings {}

次に、リフレクションを使用して注釈値にアクセスします。 JavaクラスClassは、クラスのアノテーションにアクセスするためのメソッドgetAnnotationを提供します。

Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.out.println("Hello there, " + greetings.greet() + " !!");

3. 注釈を変更する

Javaクラス クラス 注釈を管理するためのマップを維持します– Annotation クラスをキーとして、 Annotationオブジェクトを値として:

Map<Class<? extends Annotation>, Annotation> map;

このマップを更新して、実行時に注釈を変更します。 このマップにアクセスするためのアプローチは、さまざまなJDK実装で異なります。 JDK7とJDK8について説明します。

3.1. JDK7の実装

Javaクラスクラスフィールドがあります注釈。 これはプライベートフィールドであるため、アクセスするには、フィールドのアクセシビリティをtrueに設定する必要があります。 Javaはメソッドを提供します getDeclaredField 名前で任意のフィールドにアクセスするには:

Field annotations = Class.class.getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);

それでは、クラスGreeterの注釈マップにアクセスしてみましょう。

 Map<Class<? extends Annotation>, Annotation> map = annotations.get(targetClass);

これが、すべての注釈とその値オブジェクトに関する情報を含むマップです。 Greeterクラスの注釈オブジェクトを更新することで実現できるGreeter注釈値を変更します。

map.put(targetAnnotation, targetValue);

3.2. JDK8の実装

Java 8実装は、クラス内にアノテーション情報を格納します AnnotationDataannotationDataメソッドを使用してこのオブジェクトにアクセスできます。 annotationDataメソッドのアクセシビリティをtrueに設定します。これは、プライベートメソッドであるためです。

Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null);
method.setAccessible(true);

これで、annotationsフィールドにアクセスできます。 このフィールドもプライベートフィールドであるため、アクセシビリティをtrueに設定します。

Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);

このフィールドには、注釈クラスと値オブジェクトを格納する注釈キャッシュマップがあります。 それを変更しましょう:

Map<Class<? extends Annotation>, Annotation> map = annotations.get(annotationData); 
map.put(targetAnnotation, targetValue);

4. 応用

この例を見てみましょう:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");

これは、アノテーションに提供した値である「おはよう」の挨拶になります。 次に、値が「こんばんは」のGreeterタイプのオブジェクトをもう1つ作成します。

Greeter targetValue = new DynamicGreeter("Good evening");

注釈マップを新しい値で更新してみましょう。

alterAnnotationValueJDK8(Greetings.class, Greeter.class, targetValue);

挨拶の値をもう一度確認しましょう。

greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");

「こんばんは」と挨拶します。

5. 結論

Java実装は、注釈データを格納するために2つのデータフィールドを使用します: annotations describeAnnotations。 これら2つの違い:最初は親クラスからのアノテーションも保存し、後で1つは現在のクラスのみを保存します。

の実装として getAnnotation JDK7とJDK8で異なり、ここで使用します 注釈 簡単にするためのフィールドマップ。

そして、いつものように、実装のソースコードはGithub利用できます。