アノテーションは、一般的な @Override や @Deprecated などのメタデータとも呼ばれます。アノテーションは、コードを説明するために使用され、パッケージ、クラス、インターフェイス、フィールドを説明するために使用されます。 、メソッドのパラメータ、ローカルの Annotate 変数など。その主な機能は次のとおりです:
ドキュメントを生成し、コード内で識別されたメタデータを通じて javadoc ドキュメントを生成します。
コンパイルチェック。コード内で識別されるメタデータを通じて、コンパイラーはコンパイル中にチェックおよび検証できます。
コード内で識別されたメタデータによるコンパイル時の動的処理 (コードの動的生成など)。
実行時の動的処理。リフレクションインジェクションインスタンスの使用など、コード内で識別されるメタデータによる実行時の動的処理。
一般的なアノテーションは 3 つのカテゴリに分類できます:
最初のカテゴリは、@Override、@Deprecated、@SuppressWarnings などの Java 独自の標準アノテーションで、それぞれメソッドのオーバーライドとクラスのマークを示すために使用されます。または、メソッドが廃止されており、警告がこれらのアノテーションでマークされた後、コンパイラによってチェックされます。
最初のカテゴリはメタアノテーションです。メタアノテーションは、@Retention、@Target、@Inherited、@Documented などのアノテーションを定義するために使用されるアノテーションであり、アノテーションが保持される段階を示すために使用されます。 @Target はアノテーションの使用範囲を示し、@Inherited はアノテーションを継承できることを示し、@Documented は javadoc ドキュメントを生成するかどうかを示します。
最初のタイプはカスタム アノテーションです。独自のニーズに応じてアノテーションを定義でき、カスタム アノテーションにメタ アノテーションを付けることができます。
アノテーションの使用
アノテーションが必要な場所にアノテーションをマークするだけです。たとえば、メソッドにアノテーションを付けます:
public class Test { @Override public String tostring() { return "override it"; } }
たとえば、クラスにアノテーションを付けます:
@Deprecated public class Test { }
Java 組み込みのアノテーションは直接使用できますが、多くの場合、いくつかのアノテーションを自分で定義する必要があります。たとえば、共通のスプリングはオブジェクト間の依存関係を管理するために多数のアノテーションを使用します。独自のアノテーションを定義する方法を見てみましょう。そのようなアノテーションを実装してみましょう。@Test を通じて特定のクラスに文字列を注入し、@TestMethod を通じて特定のメソッドに文字列を注入します。
①Testアノテーションを作成し、クラスに作用するように宣言し、実行時まで保持します。デフォルト値はdefaultです。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Test { String value() default "default"; }
②TestMethod アノテーションを作成し、メソッドに作用するように宣言し、実行時まで保持します。
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface TestMethod { String value(); }
③テストクラスは実行後にdefaultとtomcat-methodの2つの文字列を出力します。 @Testは値を渡さないのでデフォルト値が出力され、@TestMethodは注入された文字列を出力します。
@Test() public class AnnotationTest { @TestMethod("tomcat-method") public void test(){ } public static void main(String[] args){ Test t = AnnotationTest.class.getAnnotation(Test.class); System.out.println(t.value()); TestMethod tm = null; try { tm = AnnotationTest.class.getDeclaredMethod("test",null).getAnnotation(TestMethod.class); } catch (Exception e) { e.printStackTrace(); } System.out.println(tm.value()); } }
アノテーションの原理
以前、Java の組み込みアノテーションの使用方法とアノテーションのカスタマイズ方法を紹介しました。次に、アノテーションの実装の原則を見て、大規模な Java システムでアノテーションがどのようにサポートされるかを見てみましょう。 。上記のカスタム アノテーションの例に戻りましょう。次のように、AnnotationTest クラスにアノテーションが付けられている場合、アノテーション宣言の値は AnnotationTest.class.getAnnotation(Test.class) を通じて取得できます。上記の文を見ると、クラス構造から Test アノテーションを取得していることがわかります。そのため、ある時点でアノテーションがクラス構造に追加されているはずです。
@Test("test") public class AnnotationTest { public void test(){ } }
Java ソース コードからクラス バイトコードへの変換はコンパイラによって行われ、コンパイラによって Java ソース コードが解析され、アノテーション シンボルが追加されます。クラス構造 JVM 仕様によれば、クラス ファイル構造は厳密に順序付けられた形式になっており、クラス構造に情報を追加する唯一の方法は、クラス構造の属性に保存することです。クラス、フィールド、およびメソッドには、クラス構造内に独自のテーブル構造があり、それぞれに独自の属性があることがわかります。また、アノテーションの場合、それらのアクションの範囲は、クラスまたはフィールドに対して異なる場合があります。またはメソッドを使用すると、コンパイラはクラス、フィールド、またはメソッドのプロパティにアノテーション情報を保存します。
AnnotationTest クラスがコンパイルされると、対応する AnnotationTest.class ファイルに RuntimeVisibleAnnotations 属性が含まれるようになります。このアノテーションはクラスに適用されるため、この属性はクラスの属性セットに追加されます。つまり、Test アノテーションのキーと値のペア value=test が記録されます。 JVM が AnnotationTest.class ファイルのバイトコードをロードすると、RuntimeVisibleAnnotations 属性値が AnnotationTest の Class オブジェクトに保存されるため、Test アノテーション オブジェクトは AnnotationTest.class.getAnnotation(Test.class) を通じて取得でき、次に The Test を通じて取得できます。アノテーションオブジェクトはTestで属性値を取得します。
ここで質問があるかもしれませんが、Test アノテーション オブジェクトとは何ですか?実際、コンパイルされたアノテーションの本質は Annotation インターフェイスを継承するインターフェイスであるため、@Test は実際には「パブリック インターフェイス Test extends Annotation」になります。これを AnnotationTest.class.getAnnotation(Test.class) を通じて呼び出すと、JDK は次のようになります。動的プロキシを通じて生成する Test インターフェイスを実装し、このオブジェクトに RuntimeVisibleAnnotations 属性値を設定するオブジェクト。このオブジェクトは Test アノテーション オブジェクトであり、その value() メソッドを通じてアノテーション値を取得できます。
Java アノテーション実装メカニズムの全体プロセスは上に示したとおりであり、その実装にはコンパイラーと JVM の協力が必要です。