Javaの基本:アノテーション

注釈構文

開発はまれなので、アノテーションのステータスは高くないと思う方も多いと思います。実際、クラスやインターフェースと同様に、アノテーションは1つのタイプに属します。これは、Java SE5.0バージョンで導入された概念です。

注釈の定義

アノテーションは@interfaceキーワードで定義されます

public @interface TestAnnotation {
}

その形式はインターフェースと非常に似ていますが、前に@記号が追加されています。上記のコードは、TestAnnotaionという名前の注釈を作成します

注釈の適用

アノテーションの使い方

@TestAnnotation
public class Test {
}

クラスTestを作成してから、@ TestAnnotationをクラス定義に追加して、このクラスにTestAnnotationアノテーションを付けます。

メタアノテーション

メタ注釈は、注釈に注釈を付けることができる注釈です。または、メタ注釈は基本的な注釈ですが、他の注釈に適用することもできます。

5つのメタタグがあります:@ Retention、@ Documented、@ Target、@ AliExpress、@ Repeatable

@保持

保持とは、英語での保持期間を意味します。@Retentionがアノテーションに適用されると、アノテーションの存続時間が説明されます。

その値は次のとおりです。

  • RetentionPolicy.SOURCEアノテーションは、ソースコードフェーズでのみ予約されており、コンパイラのコンパイル時に破棄され、無視されます。
  • RetentionPolicy.CLASSアノテーションは、コンパイルが進行するまでのみ保持され、JVMにはロードされません。
  • RetentionPolicy.RUNTIMEアノテーションは、プログラムが実行されるまで保持でき、JVMにロードされるため、プログラムの実行時に取得できます。

@Retentionは、ラベルにタイムスタンプをスタンプすることと同じであり、タイムスタンプは、ラベルが投稿される期間を示します。

@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}

TestAnnotationはプログラムの実行サイクル中に取得できることを指定しているため、そのライフサイクルは非常に長くなります。

@Documented

名前が示すように、このメタ注釈はドキュメントに関連している必要があります。その機能は、注釈の要素をJavadocに含めることができるようにすることです。

@目標

Targetはターゲットを意味し、@ Targetはアノテーションが適用される場所を指定します。

アノテーションが@Targetによってアノテーションされている場合、アノテーションはアプリケーションシナリオに限定されることを理解できます。

@Targetの値は次のとおりです

  • ElementType.ANNOTATION_TYPEは注釈に注釈を付けることができます
  • ElementType.CONSTRUCTORは、構築メソッドに注釈を付けることができます
  • ElementType.FIELDは属性に注釈を付けることができます
  • ElementType.LOCAL_VARIABLEは、ローカル変数に注釈を付けることができます
  • ElementType.METHODはメソッドに注釈を付けることができます
  • ElementType.PACKAGEはパッケージに注釈を付けることができます
  • ElementType.PARAMETERは、メソッド内のパラメーターに注釈を付けることができます
  • ElementType.TYPEは、クラス、インターフェイス、列挙型などの型に注釈を付けることができます

@遺伝性の

継承とは継承を意味しますが、アノテーション自体を継承できることを意味するわけではありませんが、スーパークラスに@AliExpressアノテーションが付けられている場合、そのサブクラスがアノテーションによって適用されていない場合、このサブクラスはクラスのアノテーションを継承します。スーパークラス。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}

アノテーションTestは@AliExpressによって変更され、クラスAはTestによってアノテーションが付けられ、クラスBはAを継承し、クラスBにもアノテーションTestがあります。

@Repeatable

繰り返し可能とは、当然、繰り返し可能を意味します。@RepeatableはJava1.8でのみ追加されたため、新しい機能です。

通常、注釈の値は同時に複数を取ることができます

@interface Persons {
    Person[]  value();
}
@Repeatable(Persons.class)
@interface Person{
    String role() default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}

@Repeatable注釈付きの人。@Repeatableの後の括弧内のクラスは、コンテナーアノテーションと同等です。

コンテナアノテーションとは何ですか?他の注釈を格納するために使用されます。それ自体が注釈でもあります。

@interface Persons {
    Person[]  value();
}

規則によると、その中にvalue属性が含まれている必要があります。属性タイプは、@ Repeatableでアノテーションが付けられたアノテーション配列です。配列であることに注意してください。

注釈付き属性

注釈付き属性は、メンバー変数とも呼ばれます。アノテーションにはメンバー変数のみがあり、メソッドはありません。アノテーション付きメンバー変数は、アノテーションの定義で「仮パラメーターのないメソッド」の形式で宣言されます。メソッド名はメンバー変数の名前を定義し、その戻り値はメンバー変数のタイプを定義します。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    int id();
    String msg();
}

上記のコードは、アノテーションTestAnnotationにidとmsgの2つの属性があることを定義しています。を使用するときは、それらに値を割り当てる必要があります。

割り当ての方法は、注釈の括弧内にvalue =””を使用し、複数の属性の前にそれらを使用してそれらを区切ることです。

@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}

アノテーションでプロパティを定義する場合、そのタイプは8つの基本データ型に加えて、クラス、インターフェイス、アノテーション、およびそれらの配列である必要があることに注意してください。

注釈の属性にはデフォルト値を設定でき、デフォルト値はデフォルトのキー値で指定する必要があります。といった:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Hi";
}

TestAnnotationのid属性のデフォルト値は-1であり、msg属性のデフォルト値はHiです。 
このように適用できます。

@TestAnnotation()
public class Test {}

デフォルト値があるため、@ TestAnnotationの後に括弧で囲まれた値を割り当てる必要はありません。この手順は省略できます。

さらに、別の状況があります。アノテーションにvalueという名前の属性が1つしかない場合は、このアノテーションを適用するときに、属性値を直接接続して角かっこで囲むことができます。

public @interface Check {
    String value();
}

上記のコードでは、Checkアノテーションにはvalue属性のみがあります。だからこのように適用することができます

@Check("hi")
int a;

これは次の効果と同じです

@Check(value="hi")
int a;

Javaプリセットアノテーション

@非推奨

この要素は廃止された要素をマークするために使用され、誰もが日常の開発でそれらに遭遇することが多いと思います。コンパイラがコンパイルフェーズでこのアノテーションを検出すると、警告警告を発行して、古いメソッド、古いクラス、古いメンバー変数などの古い要素が呼び出されていることを開発者に通知します。

@オーバーライド

親クラスの@Overrideによって変更されたメソッドを上書きするようにサブクラスに要求します

@SuppressWarnings

警告の意味は防止されます。@Deprecatedアノテーションが付けられたメソッドを呼び出した後、コンパイラーが警告し、開発者がこの警告を無視する場合があることを前に述べました。@ SuppressWarningsを使用して、呼び出し場所で目標を達成できます。

@SafeVarargs

パラメータの安全タイプの注釈。その目的は、安全でない操作を行うためにパラメーターを使用しないように開発者に注意を促すことであり、その存在により、コンパイラーが未チェックの警告を生成するのを防ぎます。Java1.7バージョンで追加されました。

@FunctionalInterface

関数型インターフェースアノテーション。これはJava1.8バージョンで導入された新機能です。関数型プログラミングは非常に人気があるため、Java8もこの機能をやがて追加しました。

注釈の抽出

コメントを正しくレビューすることは、手段、つまり反省と切り離せません。

注釈と反映

注釈は反射によって取得されます。まず、ClassオブジェクトのisAnnotationPresent()メソッドを使用して、特定のアノテーションが適用されているかどうかを判断できます。

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

次に、getAnnotation()メソッドを使用してAnnotationオブジェクトを取得します。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

前者のメソッドは指定されたタイプのアノテーションを返し、後者のメソッドはこの要素にアノテーションが付けられたすべてのアノテーションを返します

取得したアノテーションがnullでない場合は、それらのプロパティメソッドを呼び出すことができます。といった

@TestAnnotation()
public class Test {
    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
    }
}

プログラムの結果は

id:-1
msg:

これは、TestAnnotationのidとmsgのデフォルト値です。

上記の例では、クラスのアノテーションのみがレビューされますが、実際には、属性とメソッドのアノテーションは引き続き可能です。私はまだ私の手を反射する必要があります

@TestAnnotation(msg="hello")
public class Test {
    @Check(value="hi")
    int a;
    @Perform
    public void testMethod(){}
    @SuppressWarnings("deprecation")
    public void test1(){
        Hero hero = new Hero();
        hero.say();
        hero.speak();
    }
    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            //获取类的注解
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //获取一个成员变量上的注解
            Check check = a.getAnnotation(Check.class);
            if ( check != null ) {
                System.out.println("check value:"+check.value());
            }
            Method testMethod = Test.class.getDeclaredMethod("testMethod");
            if ( testMethod != null ) {
                // 获取方法中的注解
                Annotation[] ans = testMethod.getAnnotations();
                for( int i = 0;i < ans.length;i++) {
                    System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                }
            }
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

結果は以下のとおりです。

id:-1
msg:hello
check value:hi
method testMethod annotation:Perform

実行時にアノテーションを正常に抽出する場合は、@ Retention(RetentionPolicy.RUNTIME)が必要であることに注意してください。

アノテーションの使用シナリオ

最も厳格な公式文書

注釈は一連のメタデータであり、プログラムコードを解釈するためのデータを提供しますが、注釈は解釈されたコード自体の一部ではありません。注釈は、コードの実行効果に直接影響を与えません。

注釈には、主に次のような多くの用途があります。

  • コンパイラーに情報を提供する:コンパイラーは注釈を使用してエラーと警告を検出できます
  • コンパイル中の処理:ソフトウェアツールを使用して、注釈情報を使用してコード、HTMLドキュメント、またはその他の対応する処理を生成できます。
  • ランタイム処理:一部のアノテーションは、プログラムの実行中にコード抽出を受け入れることができます。
    アノテーションはコード自体の一部ではないことに注意してください。

注釈は主にコンパイラやその他のツールソフトウェアを対象としています

開発者がアノテーションを使用してクラス、メソッド、フィールドなどのメンバーを変更する場合、これらのアノテーションはそれ自体では有効になりません。開発者は、アノテーション情報を抽出して処理するための対応するコードを提供する必要があります。注釈を抽出して処理するためのこれらのコードは、まとめてAPT(注釈処理ツール)と呼ばれます。

特定の目的を達成するために注釈を個人的にカスタマイズする

明らかな例外についてプログラマーのコードをテストするためのテストフレームワークを作成したいと思います。

-プログラマーA:クラスを作成しました。すべてのメソッドにエラーがないため、その名前はNoBugです。 
-私:自信はいいのですが、事故を防ぐために、テストしてみませんか? 
-プログラマーA:テスト方法は? 
-私:あなたが書いたコードのメソッドに@Jiechaアノテーションを追加するだけです。 
-プログラマーA:わかりました。

package ceshi;
import ceshi.Jiecha;
public class NoBug {
    @Jiecha
    public void suanShu(){
        System.out.println("1234567890");
    }
    @Jiecha
    public void jiafa(){
        System.out.println("1+1="+1+1);
    }
    @Jiecha
    public void jiefa(){
        System.out.println("1-1="+(1-1));
    }
    @Jiecha
    public void chengfa(){
        System.out.println("3 x 5="+ 3*5);
    }
    @Jiecha
    public void chufa(){
        System.out.println("6 / 0="+ 6 / 0);
    }
    public void ziwojieshao(){
        System.out.println("我写的程序没有 bug!");
    }
}

上記のコードでは、一部のメソッドが@Jiechaアノテーションを使用しています。

このアノテーションは、私が作成したテストソフトウェアフレームワークで定義されたアノテーションです。

package ceshi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {
}

次に、NoBugの対応するメソッドをテストするためのテストクラスTestToolを作成します。

package ceshi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestTool {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        NoBug testobj = new NoBug();
        Class clazz = testobj.getClass();
        Method[] method = clazz.getDeclaredMethods();
        //用来记录测试产生的 log 信息
        StringBuilder log = new StringBuilder();
        // 记录异常的次数
        int errornum = 0;
        for ( Method m: method ) {
            // 只有被 @Jiecha 标注过的方法才进行测试
            if ( m.isAnnotationPresent( Jiecha.class )) {
                try {
                    m.setAccessible(true);
                    m.invoke(testobj, null);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                    errornum++;
                    log.append(m.getName());
                    log.append(" ");
                    log.append("has error:");
                    log.append("\n\r  caused by ");
                    //记录测试过程中,发生的异常的名称
                    log.append(e.getCause().getClass().getSimpleName());
                    log.append("\n\r");
                    //记录测试过程中,发生的异常的具体信息
                    log.append(e.getCause().getMessage());
                    log.append("\n\r");
                } 
            }
        }
        log.append(clazz.getSimpleName());
        log.append(" has  ");
        log.append(errornum);
        log.append(" error.");
        // 生成测试报告
        System.out.println(log.toString());
    }
}

テストの結果は次のとおりです。

1234567890
1+1=11
1-1=0
3 x 5=15
chufa has error:
  caused by ArithmeticException
/ by zero
NoBug has  1 error.

NoBugクラスのchufa()メソッドに例外があることを確認します。この例外の名前はArithmeticExceptionと呼ばれます。これは、操作中に0による除算が実行されるためです。

したがって、NoBugカテゴリにはバグがあります。

このように、アノテーションを通じて、他の人のコードをテストするという自分の目的を達成しました。

銀行振込の例を見てみましょう。銀行に振込サービスがあるとすると、為替レートの変化に応じて振込限度額が変わる場合があります。ビジネスコードを毎回変更する代わりに、アノテーションを使用して振込限度額を柔軟に設定できます。

/**定义限额注解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BankTransferMoney {
    double maxMoney() default 10000;
}
/**转账处理业务类*/
public class BankService {
    /**
     * @param money 转账金额
     */
    @BankTransferMoney(maxMoney = 15000)
    public static void TransferMoney(double money){
        System.out.println(processAnnotationMoney(money));

    }
    private static String processAnnotationMoney(double money) {
        try {
            Method transferMoney = BankService.class.getDeclaredMethod("TransferMoney",double.class);
            boolean annotationPresent = transferMoney.isAnnotationPresent(BankTransferMoney.class);
            if(annotationPresent){
                BankTransferMoney annotation = transferMoney.getAnnotation(BankTransferMoney.class);
                double l = annotation.maxMoney();
                if(money>l){
                   return "转账金额大于限额,转账失败";
                }else {
                    return"转账金额为:"+money+",转账成功";
                }
            }
        } catch ( NoSuchMethodException e) {
            e.printStackTrace();
        }
        return "转账处理失败";
    }
    public static void main(String[] args){
        TransferMoney(10000);
    }
}

演算結果:

转账金额为:10000.0,转账成功

注釈の役割

  • コンパイラーに情報を提供する:コンパイラーは、注釈を使用してエラーまたは警告を検出し、ログを出力できます。
  • コンパイル中の処理:ソフトウェアツールを使用して、注釈情報を使用してコード、ドキュメント、またはその他の対応する自動処理を自動的に生成できます。
  • 実行時処理:一部の注釈は、プログラムの実行時にコード抽出を受け入れ、対応する操作を自動的に実行できます。
  • 公式ドキュメントに記載されているように、アノテーションはメタデータを提供できます。転送の例では、アノテーション値を取得するプロセスは、開発者によって直接記述されたアノテーション抽出ロジックです。アノテーションを処理、抽出、処理するためのコードは、まとめて次のように呼ばれます。 APT(注釈処理ツール)。)。上記の転送例のprocessAnnotationMoneyメソッドは、APTツールクラスとして理解できます。

総括する

  • 注釈がわかりにくい場合は、ラベルと考えることができます。ラベルは物事を説明するためのものであり、注釈はコードを説明するためのものです。
  • アノテーションの基本的な構文はインターフェースのように作成されますが、@記号が追加されています。
  • 注釈のメタ注釈。
  • 注釈の属性。
  • 注釈は、主にコンパイラおよびツールタイプのソフトウェアに使用されます。
  • アノテーションの抽出には、Javaのリフレクションテクノロジーの助けが必要ですが、これは低速であるため、アノテーションを使用する際の時間コストに注意する必要があります。

https://blog.csdn.net/javazejian/article/details/71860633?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1

 

おすすめ

転載: blog.csdn.net/PrisonJoker/article/details/105400398