Annotationインタフェースの概要



今回は注釈のAnnotationインタフェースを見てみましょう.
まず、注釈とは何かを知る必要があります.注釈という特性はjava 5が導入したもので、主にコードに上元データやタグが付いています.このようにして、コードはいくつかのフレームワークの構成項目とよく結合され、コードの可読性が増加し、Hibernate注釈は非常に成功した.
Java自体は私たちに3つの注釈を提供してくれました.彼らはそれぞれ
java,lang.Override
@Override注記このメソッドが親クラスのメソッドを上書きしていることを示します.コンパイラはこのメソッドをチェックします.スペルミスが発生した場合、または親クラスがこのメソッドを報告していない場合は、エラーが発生します.
java,lang.Deprecated
@Deprecated注記は、クラス、メソッド、メンバー変数が使用されなくなったことを示し、一般的にIDEは@Deprecatedのクラス、メソッド、メンバー変数を削除して開発者に提示します.
java,lang.SuppressWarnings
@SuppressWarningsはコンパイラのwarningを除去することができ、クラス、メソッド、変数のwarningが無視できることを非常に確定したときに、この注釈を使用することができます.
では、注釈がどのように使用されているかを以下の超簡単な例で説明します.
 
@Deprecated
public class Test {

}

 Testクラスに@Deprecated注釈を追加したことがわかり、TestはIDEによって削除されました.Javaでは注釈はAnnotationのオブジェクトに反射されますが、Annotationを取得する方法はAnnotatedElementインタフェースによって実現されます.Classはちょうどこのインタフェースを実現した.
 
 
AnnotatedElementには
 T getAnnotation(Class annotationType);
boolean isAnnotationPresent(Class annotationType);
Annotation[] getAnnotations();
Annotation[] getDeclaredAnnotations();
この4つの方法.
まず、先ほどの例を例に、クラスの@Deprescated注釈オブジェクトを取得する方法を試してみましょう.
 
@Deprecated
public class Test {
	public static void main(String[] args) {
		Annotation aOverride = new Test().getClass().getAnnotation(Override.class);
		System.out.println("new Test().getClass().getAnnotation(Override.class)=" + aOverride);
		//  new Test().getClass().getAnnotation(Override.class)=null
		Annotation aDeprecated = new Test().getClass().getAnnotation(Deprecated.class);
		System.out.println("new Test().getClass().getAnnotation(Deprecated.class)=" + aDeprecated);
		//  new Test().getClass().getAnnotation(Deprecated.class)[email protected]()
	}
}

 確かにこのAnnotationを取得していることがわかりますが、注釈のタイプを事前に知らなければ取得できないことに気づきました.では、取得する注釈のタイプを判断する方法はありますか?簡単な考え方は呼び出しによって
 
boolean isAnnotationPresent(Class annotationType);
メソッドおよびif-elseは、クラスがどの注釈を使用しているかを判断し、対応するgetAnnotationメソッドを呼び出します.
 
@Deprecated
public class Test {
	public static void main(String[] args) {
		Class<? extends Test> t = new Test().getClass();
		Annotation a;
		if (t.isAnnotationPresent(Override.class)) {
			a = t.getAnnotation(Override.class);
		} else if (t.isAnnotationPresent(Deprecated.class)) {
			a = t.getAnnotation(Deprecated.class);
		} else if (t.isAnnotationPresent(SuppressWarnings.class)) {
			a = t.getAnnotation(SuppressWarnings.class);
		} else {
			a = null;
		}
		System.out.println("a=" + a);//  [email protected]()
	}
}

 コンソールでは、確かに正しい注釈オブジェクトが取得されていることがわかります.しかし、if-else文を絶えず追加するのは明らかに科学的ではありません.では、どのようにして注釈のタイプを知らないで注釈の対象を得ることができますか?AnnotatedElementインタフェースのgetAnnotationsメソッドはこの問題を解決しました.私たちはやはり上記の例を例に、@Deprescated注釈のオブジェクトを取得します.
 
 
@Deprecated
public class Test {
	public static void main(String[] args) {
		Class<? extends Test> t = new Test().getClass();
		Annotation[] arg = t.getAnnotations();
		System.out.println("arg.length=" + arg.length);//arg.length=1
		Annotation a = arg[0];
		System.out.println("a=" + a);//[email protected]()
	}
}

 コンソールでは、注釈タイプを知らずに注釈オブジェクトを取得していることがわかります.
 
getAnnotations()メソッドは、注釈タイプを知らずにクラス、メソッド、変数上のすべての注釈を取得するのに役立ちます.ここでは@MyAnnotationという注釈をカスタマイズします
 
@Inherited  
@Retention(RetentionPolicy.RUNTIME)  
public @interface MyAnnotation {
	String hello();
}

 Testクラスに注記してgetAnnotationsメソッドを呼び出します
 
@Deprecated
@MyAnnotation(hello="  ")
public class Test {
	public static void main(String[] args) {
		Class<? extends Test> t = new Test().getClass();
		Annotation[] arg = t.getAnnotations();
		System.out.println("arg.length=" + arg.length);//arg.length=2
		for (Annotation a : arg) {
			System.out.println(" a=" + a);
		}
	}
}

 私たちは2つの注釈の対象が私たちに取得されたのを見た.
 
よく見ると、AnnotatedElementクラスにはgetDeclaredAnnotationsメソッドがあり、その戻り値はgetAnnotationsメソッドと同じであることがわかります.彼らにはどんな違いがありますか?
まず、注釈は継承可能であることを知っておく必要があります.つまり、子クラスは親クラスの注釈を継承します(この注釈は定義時に@Inheritedとして宣言され、メソッドと変数の注釈は必ずしも継承できません).Testに継承するTest 2クラスをもう1つ作成します
 
@MyAnnotation(hello="  ")
class Test2 {
}

@Deprecated
public class Test extends Test2{
	public static void main(String[] args) {
		Class<? extends Test> t = new Test().getClass();
		Annotation[] ta = t.getAnnotations();
		System.out.println("ta.length=" + ta.length);
		for (Annotation temp: ta){
			System.out.println(temp);
		}
		Annotation[] tda = t.getDeclaredAnnotations();
		System.out.println("tda.length=" + tda.length);
		for (Annotation temp: tda){
			System.out.println(temp);
		}
	}
}

 コンソールにはtdaが1つの情報しか出力していないのに対し、taは2つあることがわかります.Test 2が引き継いだ@Deprescatedをtdaが遮断したからだ.
 
反射機構を用いて注釈オブジェクトを取得する方法をほぼ知った後,Annotationインタフェースがどのような方法を提供しているかを見てみよう.
まずequalsとhashの方法を見てみましょう
 
@MyAnnotation(hello="  ")
public class Test{
	public static void main(String[] args) {
		Annotation a1 = new Test().getClass().getAnnotation(MyAnnotation.class);
		Annotation a2 = new Test2().getClass().getAnnotation(MyAnnotation.class);
		boolean temp = a1.equals(a2);
		System.out.println(temp + "=Test MyAnnotation==Test2 MyAnnotation");
		System.out.println("a1=" + a1.hashCode());
		System.out.println("a2=" + a2.hashCode());
	}
}

@MyAnnotation(hello="  ")
class Test2 {
}

 コンソールからAnnotationオブジェクトには、同じ注釈であれば、どのクラスが同じ空間を指すかにかかわらず、文字列定数に似たメカニズムがあるというルールがあることがわかりました.
Annotationの別のメソッドtoSting()は、Objectのメンバー変数のようにhashcodeもオブジェクトのタイプも表示されないAnnotationオブジェクトのクラスとそのメンバー変数のみを返します.
 
最後にAnnotationクラスでは、もう一つの実用的な方法があります.
Class annotationType();
この方法は、現在の注釈オブジェクトの注釈タイプを返すことができ、これにより、注釈タイプが分からない場合に、注釈オブジェクトを取得し、そのタイプを取得して特定の処理を行うことができます.
@MyAnnotation(hello="  ")
public class Test{
	public static void main(String[] args) {
		Annotation a = new Test().getClass().getAnnotations()[0];
		Class<? extends Annotation> c = a.annotationType();
		System.out.println(c);
	}
}

 上記の例から,注釈タイプを知らない場合に注釈のオブジェクトおよび注釈タイプを取得したことが分かる.
この方法により,多くの便利で効率的な注釈反射操作を行うことができる.