Javaビルトインアノテーションの概要
1. Overview
この記事では、Java言語のコア機能であるJDKで使用可能なデフォルトのアノテーションについて説明します。
2. 注釈とは
簡単に言えば、注釈はJava types that are preceded by an “@” symbolです。
Javaには1.5リリース以降、注釈があります。 それ以来、彼らは私たちがアプリケーションを設計する方法を形作っています。
SpringとHibernateは、さまざまな設計手法を可能にするためにアノテーションに大きく依存するフレームワークの優れた例です。
基本的に、an annotation assigns extra metadata to the source code it’s bound toです。 メソッド、インターフェイス、クラス、またはフィールドに注釈を追加することにより、次のことができます。
-
警告とエラーについてコンパイラーに通知する
-
コンパイル時にソースコードを操作する
-
実行時の動作の変更または調査
3. Java組み込みアノテーション
基本を確認したので、コアJavaに付属しているいくつかのアノテーションを見てみましょう。 まず、コンパイルを通知するいくつかがあります。
-
@オーバーライド
-
しゅう
-
@非推奨
-
@SafeVarargs
-
@FunctionalInterface
これらの注釈は、コンパイラの警告とエラーを生成または抑制します。 それらを追加すると将来のプログラマーのエラーを防ぐことができるので、それらを一貫して適用することはしばしば良い習慣です。
@Overrideアノテーションは、メソッドが継承されたメソッドの動作をオーバーライドまたは置換することを示すために使用されます。
@SuppressWarningsは、コードの一部からの特定の警告を無視することを示します。 @SafeVarargsアノテーションは、可変引数の使用に関連する一種の警告にも作用します。
@Deprecatedアノテーションを使用して、APIを使用対象外としてマークすることができます。
これらすべてについて、リンクされている記事で詳細情報を見つけることができます。
3.1. @FunctionalInterface
Java 8では、より機能的な方法でコードを記述できます。
Single Abstract Method interfacesはこれの大きな部分です。 If we intend a SAM interface to be used by lambdas, we can optionally mark it as such with @FunctionalInterface:
@FunctionalInterface
public interface Adder {
int add(int a, int b);
}
メソッドを使用した@Overrideと同様に、@FunctionalInterfaceはAdderを使用して意図を宣言します。
これで、@FunctionalInterfaceを使用するかどうかに関係なく、同じ方法でAdderを使用できます。
Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);
しかし、Adder,に2番目のメソッドを追加すると、コンパイラは次のように文句を言います。
@FunctionalInterface
public interface Adder {
// compiler complains that the interface is not a SAM
int add(int a, int b);
int div(int a, int b);
}
さて、これは@FunctionalInterfaceアノテーションなしでコンパイルされたでしょう。 だから、それは私たちに何を与えますか?
@Overrideと同様に、このアノテーションは将来のプログラマーエラーから私たちを保護します。 Even though it’s legal to have more than one method on an interface, it isn’t when that interface is being used as a lambda target.このアノテーションがないと、コンパイラーは、Adderがラムダとして使用されていた数十の場所で中断します。 さて、it just breaks in Adder itself.
4. メタアノテーション
次に、メタ注釈は他の注釈に適用できる注釈です。
たとえば、これらのメタ注釈は注釈構成に使用されます。
-
@目標
-
@保持
-
@遺伝性の
-
@Documented
-
@Repeatable
4.1. @Target
注釈の範囲は、要件に応じて異なる場合があります。 アノテーションはメソッドでのみ使用されますが、コンストラクターおよびフィールド宣言で別のアノテーションを使用できます。
カスタムアノテーションのターゲット要素を決定するには、@Targetアノテーションでラベルを付ける必要があります。
@Targetはeight different element typesと連携できます。 @SafeVarargsのソースコードを見ると、コンストラクターまたはメソッドにのみアタッチする必要があることがわかります。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {
}
4.2. @Retention
一部の注釈はコンパイラのヒントとして使用されることを意図しており、その他の注釈は実行時に使用されます。
We use the @Retention annotation to say where in our program’s lifecycle our annotation applies。
これを行うには、次の3つの保持ポリシーのいずれかを使用して@Retentionを構成する必要があります。
-
RetentionPolicy.SOURCE –はコンパイラにもランタイムにも表示されません
-
RetentionPolicy.CLASS –コンパイラーによって表示されます
-
コンパイラとランタイムから見えるRetentionPolicy.RUNTIME –
@RetentionのデフォルトはRetentionPolicy.SOURCEです。
実行時にアクセスできる注釈がある場合:
@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RetentionAnnotation {
}
次に、いくつかの注釈をクラスに追加すると:
@RetentionAnnotation
@Deprecated
public class AnnotatedClass {
}
これで、AnnotatedClassを振り返って、保持されている注釈の数を確認できます。
@Test
public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
AnnotatedClass anAnnotatedClass = new AnnotatedClass();
Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
assertThat(annotations.length, is(1));
}
値は1です。 @RetentionAnnotationにはRUNTIMEの保持ポリシーがありますが、@Deprecatedにはありません。
4.3. @Inherited
状況によっては、アノテーションを親クラスにバインドするためにサブクラスが必要になる場合があります。
@Inheritedアノテーションを使用して、アノテーションをアノテーション付きクラスからそのサブクラスに伝播させることができます。
カスタムアノテーションに@Inheritedを適用してから、BaseClassに適用すると次のようになります。
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}
@InheritedAnnotation
public class BaseClass {
}
public class DerivedClass extends BaseClass {
}
次に、BaseClassを拡張した後、実行時にDerivedClassが同じアノテーションを持っているように見えるはずです。
@Test
public void whenAnnotationInherited_thenShouldExist() {
DerivedClass derivedClass = new DerivedClass();
InheritedAnnotation annotation = derivedClass.getClass()
.getAnnotation(InheritedAnnotation.class);
assertThat(annotation, instanceOf(InheritedAnnotation.class));
}
@Inheritedアノテーションがないと、上記のテストは失敗します。
4.4. @Documented
デフォルトでは、JavaはJavadocでの注釈の使用法を文書化しません。
But, we can use the @Documented annotation to change Java’s default behavior。
@Documentedを使用するカスタムアノテーションを作成する場合:
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
int value();
}
そして、適切なJava要素に適用します。
public class Employee {
@ExcelCell(0)
public String name;
}
次に、EmployeeJavadocは注釈の使用法を明らかにします。
4.5. @Repeatable
特定のJava要素に同じ注釈を複数回指定すると便利な場合があります。
Java 7より前は、アノテーションを1つのコンテナアノテーションにグループ化する必要がありました。
@Schedules({
@Schedule(time = "15:05"),
@Schedule(time = "23:00")
})
void scheduledAlarm() {
}
ただし、Java 7はよりクリーンなアプローチをもたらしました。 Withthe @Repeatable annotation,we can make an annotation repeatable:
@Repeatable(Schedules.class)
public @interface Schedule {
String time() default "09:00";
}
@Repeatableを使用するには、コンテナアノテーションも必要です。.この場合、@Schedulesを再利用します。
public @interface Schedules {
Schedule[] value();
}
もちろん、これはJava 7以前のバージョンとよく似ています。 ただし、現在の値は、@Scheduleを繰り返す必要があるときに、ラッパー@Schedulesが指定されなくなったことです。
@Schedule
@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {
}
Javaにはラッパーアノテーションが必要なため、Java 7より前のアノテーションリストから繰り返し可能なアノテーションに簡単に移行できました。
5. 結論
この記事では、すべてのJava開発者が精通している必要のあるJava組み込みアノテーションについて説明しました。
いつものように、記事のすべての例はover on GitHubで見つけることができます。