Java 5.0 Tiger では、標準のアノテーションとして @Override
, @Deprecated
, @SuppressWarnings
などが定義されました。
このようなアノテーションは、自由に定義することができます。
アノテーションを定義するには、@interface
というキーワードを使用します。
下記はシンプルなアノテーションの例で、単純にマーカーとしての役割を果たします。
package com.example.annotation;
/**
* Denotes that a parameter, field or method return value can never be null.
*/
public @interface NonNull {
}
上記のように定義したアノテーションは、標準のアノテーションと同様に使用することができます。
package com.example;
import com.example.annotation.NonNull;
public class Hello {
@NonNull
private static Hello getInstance() {
return new Hello();
}
}
アノテーションには、任意の数のメンバを持たせることができます。 アノテーションのメンバは、ちょっと特殊な構文で下記のように定義します。
package com.example.annotation;
public @interface ReviewedBy {
String reviewer();
String date();
}
アノテーションを使用するときは、キー&バリューの形でパラメータを指定します。
package com.example;
import com.example.annotation.ReviewedBy;
@ReviewedBy(reviewer = "maku", date = "2015-10-05")
public class Hello {
// ...
アノテーションのメンバには、デフォルト値を指定しておくこともできます。
public @interface ReviewedBy {
String reviewer() default "maku";
String date();
}
デフォルト値が指定されている場合は、アノテーションを使用するときに、そのパラメータを省略することができます。
@ReviewedBy(date = "2015-10-05")
public class Hello {
// ...
アノテーションのメンバとして配列を持たせることもできます。
public @interface Author {
String[] authors();
}
配列メンバを持つアノテーションを使用するときは、下記のように { }
を使ってパラメータを渡します。
@Author(authors = {"maku", "moja"})
public class Sample {
// ...
単一要素をパラメータとして渡す場合は、{ }
を省略することができます。
@Author(authors = "maku")
public class Sample {
// ...
アノテーションの定義の中で、パラメータに使用する Enum 値を定義しておくことができます。
package com.example.annotation;
public @interface NeedReview {
public enum Severity {
HIGH, MIDDLE, LOW
};
String note();
Severity severity() default Severity.MIDDLE;
}
定義した Enum 値は、通常の Java コードと同じ感覚で使用することができます。
package com.example;
import com.example.annotation.NeedReview;
@NeedReview(
note = "This code is dangerous!",
severity = NeedReview.Severity.HIGH)
public class Sample {
// ...
アノテーションのメンバ名として value という名前のフィールドをひとつだけ持つように定義しておくと、アノテーションを使用するときに、そのフィールド名を省略してパラメータを渡せるようになります。
public @interface Author {
String[] value();
}
@Author({"maku", "moja"})
public class Sample {
// ...
アノテーションを定義するときに付加できるアノテーション(メタアノテーション)が用意されており、これを使用すると、アノテーションの特性や使い方を制御することができます。
独自のアノテーションを定義する際に、@Target メタアノテーションを指定しておくと、どのようなタイプの要素に対して、そのアノテーションを付加できるのかを制御することができます。 タイプは java.lang.annotation.ElementType で定義されており、下記のようなものを指定することができます。
例えば、メソッドとパラメータ、フィールドにだけ付加できる NonNull
アノテーションを定義するには、下記のようにします。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NonNull {}
独自のアノテーションを定義する際に、@Retention メタアノテーションを指定しておくと、そのアノテーション情報をどの段階まで保持するかを制御できます。 段階は、java.lang.annotation.RetentionPolicy で定義されており、下記のような値を指定することができます。
RetentionPolicy として SOURCE を指定すると、コンパイル時にアノテーション情報は破棄されます。 CLASS(デフォルト)を指定すると、クラスファイルにアノテーション情報は含まれますが、実行時に VM で無視されます。 RUNTIME を指定すると、実行時に VM から参照することができます。
例えば、下記のように RetentionPolicy として RUNTIME を指定しておくと、
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String[] value();
}
Java プログラムの中から、下記のようにアノテーション情報にアクセスすることができるようになります。
@Author("maku")
public class Sample {
public static void main(String[] args) {
for (Annotation anno : Sample.class.getAnnotations()) {
System.out.println(anno); // @com.example.annotation.Author(value=[maku])
}
}
}
デフォルトでは、独自アノテーションを付けたクラスの Javadoc API ドキュメントを出力しても、そこにはアノテーション情報は表示されません。 アノテーション情報を API ドキュメントに含めるには、@Documented メタアノテーションを付加した状態で、独自アノテーションを定義する必要があります。
@Documented
public @interface ToDo {
String[] value();
}