JAva注釈の詳細とカスタム注釈

9501 ワード

本稿ではまず注釈の基本概念とJDKに組み込まれた標準注釈を紹介し,次に注釈をカスタマイズする方法を紹介し,最後に注釈をカスタマイズする例を示した.
一、注釈の基本概念
Java注記は、修飾子のようにjavaコードからドキュメントを抽出したり、コードの依存性を追跡したり、コンパイル時にチェックしたりするために使用できます.注記は、パッケージ、クラス、メソッド、メンバー変数、パラメータ、およびローカル変数の宣言に適用できます.私たちの多くの人が最初に接触した注釈は@Overrideです.
注釈の動作原理は、まず注釈を使用してjavaコードを修飾し、その後、もう一つの注釈プロセッサというコードがこの注釈と修飾されたコードを解析し、対応する処理を行うことです.
二、JDK内蔵の標準注記
JavaSEには3つの標準注釈が内蔵されており、javaに定義されている.langでは、次のとおりです.
  • @Override:子クラスを修飾する方法は親クラスのメソッドを上書きします.
  • @Deprecated:古い方法を修飾するために使用され、使用する方法は推奨されません.
  • @SuppressWarnnings:javaコンパイラにコンパイル禁止警告を伝えます.

  • 2.1 @Override
    @Overrideは簡単で、メソッドをマークするためのタグにすぎません.これは、親クラスのメソッドが寸法付けされたメソッドで上書きされていることを示します.うっかりすると、サブクラスのメソッド名が書き間違えて、@Overrideができた後、コンパイル時にエラーが報告されます.つまり@Overrideで表記されているメソッドが親を上書きしていない場合は、コンパイル時にエラーが発生します.
    2.2 @Deprecated
    @Deprescatedもタグ注記であり、メソッドを修飾するために使用されます.これは、この方法が推奨されていないことを示します.コンパイラは、このメソッドを継承、上書き、または直接使用する場合に警告します.
    2.3 @SuppressWarnings
    字面翻訳は警告を抑制し、コンパイラに表示されたこのコードに特定の警告を与えないように伝えるために使用されます.
    @SuppressWarningsには、特定の警告を表すパラメータがあります.
  • deprecation:「使用に賛成しないクラスやメソッドの警告」を与えないでください.
  • unchecked:「タイプ変換時の警告」を与えないでください.
  • fallthrough:switch文ブロックにbreakの警告は与えないでください.
  • path:「存在しないパス」の警告を与えないでください.
  • serial:「シリアル可能クラスにserialVersionUIDが欠けている」という警告を与えないでください.
  • finally:「finally文ブロックが正常に完了しない」という警告を与えないでください.
  • all:以上のすべての状況に警告しないでください.

  • 三、カスタム注釈
    JAvaでは、カスタム注釈に使用するメタ注釈を提供する注釈を独自に定義できます.
    3.1元注記
    JAvaがメタ注釈を提供する目的は,開発者にカスタム注釈をカスタマイズさせることであり,メタ注釈はカスタム注釈を注釈する責任を負う.
  • @Target;
  • @Retention;
  • @Documented;
  • @Inherited.

  • Java5.0は4つのメタ注記を定義します.次に、この4つの要素注記をそれぞれ分析します.
    3.1.1 @Target
    @Targetは、カスタム注釈がどこで使用できるかを説明するために使用されます.そのElementTypeの値は:1です.CONTRUCTOR:コンストラクタ2を記述するために用いる.FIELD:ドメイン3の記述に用いる.LOCAL_VARABLE:局所変数4を記述するために用いる.METHOD:説明方法5に用いる.PACKAGE:パケット6を記述するためのものである.PARAMETER:パラメータ7の記述に用いる.TYPE:クラス、インタフェース(注釈タイプを含む)またはenum宣言の記述に使用
    使用例:@Target(ElementType.FIELD)
    3.1.2 @Retention
    @Retentionは、カスタム注釈のライフサイクルを記述するために使用され、RetentionPoicyの値は:1.SOURCE:ソースファイルで有効2.CLASS:classファイルで有効3.RUNTIME:実行時に有効
    使用例:@Retention(RetentionPolicy.RUNTIME)
    3.1.3 @Documented
    @Documentedは、カスタム注釈がjavadocなどのツールでドキュメント化され、メンバーがいないことを示すために使用されます.
    使用例:@Documented
    3.1.4 @Inherited
    @Inheritedメタ注釈はタグ注釈であり、@Inheritedはある注釈のタイプが継承されていることを述べている.@Inherited修飾を使用したannotationタイプがclassに使用される場合、このannotationはclassのサブクラスに使用されます.
    @Inherited annotationタイプは、マークされたclassのサブクラスに継承されます.クラスは、実装されたインタフェースからannotationを継承しません.メソッドは、再ロードされたメソッドからannotationを継承しません.
    @Inherited annotationタイプ表記のannotationのRetentionがRetentionPolicyである場合RUNTIMEでは、反射APIがこの継承性を強化する.Javaを使用するとlang.reflect@Inherited annotationタイプのannotationをクエリーすると、反射コードチェックが展開されます.classとその親クラスが、指定したannotationタイプが発見されるまで、またはクラス継承構造の最上位に到達するまでチェックします.
    使用例:@Inherited
    3.2カスタム注釈の開始
    注記のフォーマットを定義するには、次の手順に従います.
    public@interface注記名{定義体}
    注記パラメータのサポート可能なデータ型:
  • すべての基本データ型(int,float,boolean,byte,double,char,long,short)
  • Stringタイプ
  • Classタイプ
  • enumタイプ
  • Annotationタイプ
  • 以上のすべてのタイプの配列
  • @interfaceを使用して注釈をカスタマイズするとjavaが自動的に継承されます.lang.annotation.Annotationインタフェースは、コンパイラによって自動的に他の詳細を完了します.注記を定義するときに、他の注記やインタフェースを継承することはできません.
    @interfaceは注釈を宣言するために使用され、各メソッドは実際に構成パラメータを宣言します.メソッドの名前はパラメータの名前で、戻り値タイプはパラメータのタイプです(戻り値タイプは基本タイプ、Class、String、enumのみ).defaultでパラメータのデフォルト値を宣言できます.
    注意:
  • はpublicまたはデフォルト(default)の2つのアクセス権でのみ修飾できる.たとえば、String value()ここではメソッドをdefaulデフォルトタイプに設定します. 
  • パラメータメンバーは、基本タイプbyte、short、char、int、long、float、double、booleanの8種類の基本データ型とString、Enum、Class、annotationsなどのデータ型、およびこれらのタイプの配列しか使用できない.たとえば、String value()ここのパラメータメンバーはStringです.  
  • パラメータメンバーが1つしかない場合は、パラメータ名を「value」に設定し、カッコを付けることが望ましい.

  • 3.3例
    注記@Persionを定義します.
    package com.zcx.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Persion {
        String name() default "zcx";
        int age() default 18;
    
        String[] hobby() default {"basketball", "football"};
    }
    

    注記@StudentGenderをもう1つ定義します.
    package com.zcx.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface StudentGender {
    
        public enum Gender{BOY, GIRL};
        Gender gender() default Gender.BOY;
    
    }

    定義した2つの注記を使用してクラスを定義します.
    package com.zcx.annotation;
    
    import com.zcx.annotation.StudentGender.Gender;
    
    @Persion(name="haha", age=97, hobby={"test1", "test2"})
    public class Student {
    
    
        @StudentGender(gender=Gender.BOY)
        private String stuGender;
    
    
        public String getStuGender() {
            return stuGender;
        }
        public void setStuGender(String stuGender) {
            this.stuGender = stuGender;
        }
    }

    注釈の内容を処理する注釈プロセッサを定義します.
    package com.zcx.annotation;
    
    import java.lang.reflect.Field;
    
    
    public class AnnotationProcessor {
        public static void getStudentInfo(Class> clazz){
            if(clazz.isAnnotationPresent(Persion.class)){
                Persion annotation = (Persion)clazz.getAnnotation(Persion.class);
                System.out.println(annotation);
                System.out.println(annotation.age());
                System.out.println(annotation.name());
                String[] hobby = annotation.hobby();
                for(String str : hobby){
                    System.out.println(str);
                }
            }
            Field[] fields = clazz.getDeclaredFields();
    
            for(Field field :fields){
                System.out.println("fieldName=" + field.toString());
                if(field.isAnnotationPresent(StudentGender.class)){
                    StudentGender annotation = (StudentGender)field.getAnnotation(StudentGender.class);
                    System.out.println(annotation);
                    System.out.println(annotation.gender());
                }
            }
        }
    }
    

    最後に、テストクラスを定義します.
    package com.zcx.annotation;
    
    public class Test {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            AnnotationProcessor.getStudentInfo(Student.class);
        }
    }