Javaの——注釈の詳細とカスタム注釈(JDKに基づいて簡単な注釈機能を実現する)

7250 ワード

転載は出典を明記してください.https://blog.csdn.net/l1028386804/article/details/80275085
一、注釈の基本概念
Java注記は、修飾子のようにjavaコードからドキュメントを抽出したり、コードの依存性を追跡したり、コンパイル時にチェックしたりするために使用できます.注記は、パッケージ、クラス、メソッド、メンバー変数、パラメータ、およびローカル変数の宣言に適用できます.私たちの多くの人が最初に接触した注釈は@Overrideです.
注釈の動作原理は、まず注釈を使用してjavaコードを修飾し、その後、もう一つの注釈プロセッサというコードがこの注釈と修飾されたコードを解析し、対応する処理を行うことです.
二、JDK内蔵の標準注記
JavaSEには、Java.langで定義された3つの標準注釈が内蔵されています.
  • @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.

  • Java 5.0では、4つのメタ注釈が定義されています.次に、この4つの要素注記をそれぞれ分析します.
    3.1.1 @Target
    @Targetは、カスタム注釈がどこで使用できるかを説明するために使用されます.そのElementTypeは、1.CONTRUCTOR:コンストラクタを記述するために使用されます.2.FIELD:ドメインを記述するために使用されます.3.LOCAL_VARIABLE:ローカル変数を記述するための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をクエリーすると、指定したannotationタイプが発見されるか、クラス継承構造の最上位に到達するまでclassとその親クラスをチェックします.
    使用例:@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例
    注記@Infoを定義
    package io.mykit.annotation.jdk.provider;
    
    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;
    
    /**
     *       Info  
     * @author liuyazhuang
     *
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Info {
    	String name() default "liuyazhuang";
    	int age() default 18;
    	String[] hobby() default {"basketball", "football"};
    }
    

    注記をもう1つ定義@Gender
    package io.mykit.annotation.jdk.provider;
    
    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;
    
    /**
     *       
     * @author liuyazhuang
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Gender {
    	
    	public enum GenderEnum{BOY, GIRL}
    	
    	GenderEnum gender() default GenderEnum.BOY;
    }

    先に定義した2つの注記を使用して、Userクラスを定義します.
    package io.mykit.annotation.jdk.provider.entity;
    
    import io.mykit.annotation.jdk.provider.Gender;
    import io.mykit.annotation.jdk.provider.Info;
    import io.mykit.annotation.jdk.provider.Gender.GenderEnum;
    
    /**
     *        
     * @author liuyazhuang
     *
     */
    @Info(name="liuyazhuang", age = 18, hobby = {"Java", "C", "Python", "Go"})
    public class User {
    	
    	@Gender(gender = GenderEnum.BOY)
    	private String sex;
    
    	public String getSex() {
    		return sex;
    	}
    
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	
    }
    は、注釈の内容を処理する注釈プロセッサAnnotationProcessを定義する.
    package io.mykit.annotation.jdk.provider.parser;
    
    import java.lang.reflect.Field;
    
    import io.mykit.annotation.jdk.provider.Gender;
    import io.mykit.annotation.jdk.provider.Info;
    
    /**
     *   Info   Gender  
     * @author liuyazhuang
     *
     */
    public class AnnotationProcessor {
    	/**
    	 *   clazz        
    	 * @param clazz:    clazz  
    	 */
    	public static void parseAnnotation(Class> clazz){
    		//clazz  Info    
    		if(clazz.isAnnotationPresent(Info.class)){
    			//  Info  
    			Info annotation = clazz.getAnnotation(Info.class);
    			System.out.println(annotation);
    			System.out.println(annotation.name());
    			System.out.println(annotation.age());
    			String[] bobby = annotation.hobby();
    			for(String str : bobby){
    				System.out.println(str);
    			}
    		}
    		Field[] fields = clazz.getDeclaredFields();
    		if(fields != null && fields.length > 0){
    			for(Field field : fields){
    				if(field.isAnnotationPresent(Gender.class)){
    					Gender annotation = field.getAnnotation(Gender.class);
    					System.out.println(annotation);
    					System.out.println(annotation.gender());
    				}
    			}
    		}
    	}
    }
    最後に、テストクラスを定義します.
    package io.mykit.annotation.jdk.provider;
    
    import org.junit.Test;
    
    import io.mykit.annotation.jdk.provider.entity.User;
    import io.mykit.annotation.jdk.provider.parser.AnnotationProcessor;
    
    /**
     *        
     * @author liuyazhuang
     *
     */
    public class AnnotationTest {
    	
    	@Test
    	public void testAnnotation(){
    		AnnotationProcessor.parseAnnotation(User.class);
    	}
    }

    テスト結果は次のとおりです.
    @io.mykit.annotation.jdk.provider.Info(name=liuyazhuang, age=18, hobby=[Java, C, Python, Go])
    liuyazhuang
    18
    Java
    C
    Python
    Go
    @io.mykit.annotation.jdk.provider.Gender(gender=BOY)
    BOY