[Java の基本] アノテーション - カスタム アノテーション

注釈とは何ですか?

Java アノテーション (Annotation) は、Java アノテーションとも呼ばれ、JDK5.0 によって導入されたアノテーション メカニズムです。たとえば、一般的な @Override と @Deprecated は両方ともアノテーションであり、クラス、メソッド、メンバー変数などに「ラベルを付ける」のと同様に、アノテーションを追加できます

アノテーションはどのように定義されますか?

パブリック @interface アノテーション名 {} は、追加の @ シンボル インターフェイスがあることを除いて、定義インターフェイスと非常によく似ています:パブリック インターフェイス インターフェイス名アノテーション:パブリック @インターフェイス アノテーション名

public @interface lkx {
    
    
    
}

注釈を使用するにはどうすればよいですか?

アノテーションの定義が完了したので、アノテーションを使用する際に「 @ アノテーション名」を直接使用できるようになり、例えば以下のように「クラス、メンバ変数、メンバメソッド」に定義することができます。

@lkx
public class Test {
    
    
    @lkx
    private int num;
    
    @lkx
    public static void main(String[] args) {
    
    
        System.out.println("hello");
    }
}
  • しばらく考えてみる

アノテーションを定義して使用しましたが、クラスまたはメンバー メソッドに定義するのではなく、メンバー メソッドにのみ定義したいのです。アノテーションをメソッドとレポートにのみ定義するにはどうすればよいですか?他の場所で定義されているとエラーになりますか? 望ましい効果: ここに画像の説明を挿入

このとき、メタアノテーションを利用して範囲を制限する必要があります。

メタアノテーション

平たく言えば、メタアノテーションはannotations に定義されたアノテーションですJava には 4 つのメタアノテーションがあります @Target @Retention @Documented @Inherited

@目標

@Target はアノテーションの定義範囲を記述するために使用され、このアノテーションで定義される要素の型を制限できます。

パラメータ 効果
ElementType.ANNOTATION_TYPE 注釈タイプに適用可能
要素タイプ.CONSTRUCTOR コンストラクターに適用できます
要素タイプ.フィールド フィールドまたはプロパティに適用可能
ElementType.LOCAL_VARIABLE ローカル変数に適用できる
要素タイプ.メソッド メソッドレベルのアノテーションに適用可能
要素タイプ.パッケージ パッケージ宣言に適用可能
要素タイプ.PARAMETER メソッドに適用できるパラメータ
要素タイプ.TYPE クラスの任意の要素に適用できます

メンバー変数のみに制限したいため、ElementType.FIELDを使用する必要があります。

@Target(ElementType.FIELD)
public @interface lkx {
    
    

}

しかし、メンバー変数とメンバー メソッドの両方を同時に定義したい場合はどうすればよいでしょうか?複数のパラメーターは中括弧で囲み、カンマで区切るだけで済みます。

@Target({
    
    ElementType.FIELD,ElementType.METHOD})
public @interface lkx {
    
    

}

クラスに定義されたアノテーションのみがエラーを報告するようになりました。ここに画像の説明を挿入

@保持

@Retention は、アノテーションのライフサイクルを定義するために使用され、保管方法としても理解できます。

パラメータ 効果
RetentionPolicy.SOURCE マークされたアノテーションはソース レベルでのみ保持され、コンパイラによって無視されます。
RetentionPolicy.CLASS マークされたアノテーションはコンパイル時にコンパイラーによって保存されますが、Java 仮想マシン (JVM) によって無視されます。
RetentionPolicy.RUNTIME マークされたアノテーションは JVM によって保存されるため、ランタイム環境で使用できます。

以下の 2 つのメタアノテーションはあまり使用されないため、当面は詳細な説明は省略します。

@文書化されました

@Documented は、ヘルプドキュメントを生成するときにその注釈情報を保持するかどうかを記述するために使用されます。

@遺伝性の

@Inherited は、それによって変更されたアノテーションが継承されるかどうかを記述するために使用されます。

注釈要素

上ではアノテーションを定義しましたが、情報を渡すことはできません。これは単にラベルと同等です。次に、アノテーションのパラメータを定義する方法を見てみましょう:

@Target({
    
    ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface lkx {
    
    
    String name() default "张三"; //可以使用default定义默认的值
    int age();
}

次に、パラメータを渡す方法を見てみましょう。

public class Test {
    
    

    //name有默认值,也可以不写
    @lkx(name = "李四",age = 18)
    private int num;
    
    public static void main(String[] args) {
    
    
        System.out.println("hello");
    }
}

戦闘

アノテーションが定義され、パラメータが渡されたところで、アノテーションが何に役立つのかまだ疑問に思いませんか? ここで、アノテーションで渡されたパラメータをメンバー変数に割り当てるという小さな要件があります。例えば:

@lkx(name = "李四",age = 18)
private int num; //num没有被赋值,等于0

赋值完成后
num = 18

予防:

  1. 次のコードではリフレクションを使用する必要があります。その方法がわからない場合は、以前の記事を参照してください。
  2. 注釈パラメーターを取得するにはリフレクションを使用する必要があるため、@Retention を RetentionPolicy.RUNTIME として定義する必要があります。

実装コード:

@Target({
    
    ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface lkx {
    
    
    String name() default "张三";
    int age();
}
java复制代码public class Test {
    
    

    //name有默认值,也可以不写
    @lkx(name = "李四",age = 18)
    private static int num;

    @lkx(name = "王五",age = 38)
    private static int age;

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    
    
        System.out.println("赋值前: num: " + num+"   age: "+age);

        //拿到类的字节码
        Class<Test> testClass = Test.class;
        //拿到所有成员变量
        for (Field declaredField : testClass.getDeclaredFields()) {
    
    
            //检测成员变量上是否有@lkx注解
            if (declaredField.isAnnotationPresent(lkx.class)) {
    
    
                lkx annotation = declaredField.getAnnotation(lkx.class);
                //获取到注解中的age的值
                int age = annotation.age();
                declaredField.set(testClass.newInstance(),age);
            }
        }

        System.out.println("赋值后: num: " + num+"   age: "+age);
    }
}

操作結果:

java复制代码赋值前: num: 0   age: 0
赋值后: num: 18   age: 38

おすすめ

転載: blog.csdn.net/weixin_50799082/article/details/131236558