Java組み込みアノテーションの概要

1.概要

この記事では、Java言語のコア機能であるJDKで使用可能なデフォルトのアノテーションについて説明します。

2.注釈とは

簡単に言うと、アノテーションは「@」記号が前に付いたJavaタイプです

Javaには、1.5リリース以来ずっとアノテーションがあります。それ以来、それらは私たちがアプリケーションを設計する方法を形作っています。

SpringとHibernateは、さまざまな設計手法を可能にするために注釈に大きく依存するフレームワークの優れた例です。

基本的に、アノテーション、バインドされているソースコードに追加のメタデータを割り当てます。メソッド、インターフェイス、クラス、またはフィールドにアノテーションを追加することで、次のことができます。

  1. 警告とエラーについてコンパイラに通知します
  2. コンパイル時にソースコードを操作する
  3. 実行時の動作を変更または調査する

3.Java組み込みアノテーション

基本を確認したので、コアJavaに付属しているいくつかのアノテーションを見てみましょう。まず、コンパイルを通知するものがいくつかあります。

  1. @オーバーライド
  2. @SuppressWarnings
  3. @非推奨
  4. @SafeVarargs
  5. @FunctionalInterface
  6. @ネイティブ

これらの注釈は、コンパイラの警告とエラーを生成または抑制します。それらを一貫して適用することは、将来のプログラマーのエラーを防ぐことができるため、多くの場合、良い習慣です。

@Overrideのアノテーションは、メソッドオーバーライドまたは継承されたメソッドの動作を置き換えることを示すために使用されます。

@SuppressWarningsは、コードの一部からの特定の警告を無視することを示します。@SafeVarargs注釈はまた、可変引数を使用してに関連する警告のタイプに作用します。

@Deprecated注釈はもう使用することを意図していないとして、APIをマークするために使用することができます。さらに、このアノテーションはJava 9に後付けされ、非推奨に関する詳細情報を表しています。

これらすべてについて、リンクされている記事でより詳細な情報を見つけることができます。

3.1。@FunctionalInterface

Java 8を使用すると、より機能的な方法でコードを記述できます。

シングル抽象メソッドインターフェイスは、これの大きな部分です。私たちはラムダが使用するSAMインターフェイスをする場合は、我々は、必要に応じてそのようにマークすることができ@FunctionalInterface

@FunctionalInterface public interface Adder { int add(int a, int b); }

@Override withメソッドと同様に、@ FunctionalInterfaceAdderを使用して意図を宣言します。

これで、@ 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と同様に、このアノテーションは将来のプログラマーエラーから私たちを保護します。1つのインターフェースに複数のメソッドを設定することは合法ですが、そのインターフェースがラムダターゲットとして使用されている場合はそうではありません。このアノテーションがないと、コンパイラはAdderがラムダとして使用されていた数十の場所で機能しなくなります。さて、それはAdder自体に侵入するだけです。

3.2。@ネイティブ

Java 8以降、java.lang.annotationパッケージにNativeという新しいアノテーションがあります@Native注釈はフィールドにのみ適用されます。これは、注釈付きフィールドがネイティブコードから参照される可能性のある定数であることを示しています。たとえば、Integerクラスでの使用方法は次のとおりです。

public final class Integer { @Native public static final int MIN_VALUE = 0x80000000; // omitted }

この注釈は、ツールがいくつかの補助ヘッダーファイルを生成するためのヒントとしても役立ちます。

4.メタアノテーション

次に、メタアノテーションは他のアノテーションに適用できるアノテーションです。

たとえば、これらのメタ注釈は注釈の構成に使用されます。

  1. @目標
  2. @保持
  3. @遺伝性の
  4. @Documented
  5. @Repeatable

4.1。@目標

The scope of annotations can vary based on the requirements. While one annotation is only used with methods, another annotation can be consumed with constructor and field declarations.

To determine the target elements of a custom annotation, we need to label it with a @Target annotation.

@Target can work with eight different element types. If we look at the source code of @SafeVarargs, then we can see that it must be only attached to constructors or methods:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) public @interface SafeVarargs { }

4.2. @Retention

Some annotations are meant to be used hints for the compiler, while others are used at runtime.

We use the @Retention annotation to say where in our program's lifecycle our annotation applies.

To do this, we need to configure @Retention with one of three retention policies:

  1. RetentionPolicy.SOURCE – visible by neither the compiler nor the runtime
  2. RetentionPolicy.CLASS – visible by the compiler
  3. RetentionPolicy.RUNTIME – visible by the compiler and the runtime

@Retention defaults to RetentionPolicy.SOURCE.

If we have an annotation that should be accessible at runtime:

@Retention(RetentionPolicy.RUNTIME) @Target(TYPE) public @interface RetentionAnnotation { }

Then, if we add some annotations to a class:

@RetentionAnnotation @Deprecated public class AnnotatedClass { }

Now we can reflect on AnnotatedClass to see how many annotations are retained:

@Test public void whenAnnotationRetentionPolicyRuntime_shouldAccess() { AnnotatedClass anAnnotatedClass = new AnnotatedClass(); Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations(); assertThat(annotations.length, is(1)); }

The value is 1 because @RetentionAnnotation has a retention policy of RUNTIME while @Deprecated doesn't.

4.3. @Inherited

In some situations, we may need a subclass to have the annotations bound to a parent class.

We can use the @Inherited annotation to make our annotation propagate from an annotated class to its subclasses.

If we apply @Inherited to our custom annotation and then apply it to BaseClass:

@Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface InheritedAnnotation { } @InheritedAnnotation public class BaseClass { } public class DerivedClass extends BaseClass { }

Then, after extending the BaseClass, we should see that DerivedClass appears to have the same annotation at runtime:

@Test public void whenAnnotationInherited_thenShouldExist() { DerivedClass derivedClass = new DerivedClass(); InheritedAnnotation annotation = derivedClass.getClass() .getAnnotation(InheritedAnnotation.class); assertThat(annotation, instanceOf(InheritedAnnotation.class)); }

Without the @Inherited annotation, the above test would fail.

4.4. @Documented

By default, Java doesn't document the usage of an annotation in Javadocs.

But, we can use the @Documented annotation to change Java's default behavior.

If we create a custom annotation that uses @Documented:

@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelCell { int value(); }

And, apply it to the appropriate Java element:

public class Employee { @ExcelCell(0) public String name; }

Then, the Employee Javadoc will reveal the annotation usage:

4.5. @Repeatable

Sometimes it can be useful to specify the same annotation more than once on a given Java element.

Before Java 7, we had to group annotations together into a single container annotation:

@Schedules({ @Schedule(time = "15:05"), @Schedule(time = "23:00") }) void scheduledAlarm() { }

However, Java 7 brought a cleaner approach. With the @Repeatable annotation, we can make an annotation repeatable:

@Repeatable(Schedules.class) public @interface Schedule { String time() default "09:00"; }

To use @Repeatable, we need to have a container annotation, too. In this case, we'll reuse @Schedules:

public @interface Schedules { Schedule[] value(); }

Of course, this looks a lot like what we had before Java 7. But, the value now is that the wrapper @Schedules isn't specified anymore when we need to repeat @Schedule:

@Schedule @Schedule(time = "15:05") @Schedule(time = "23:00") void scheduledAlarm() { }

Because Java requires the wrapper annotation, it was easy for us to migrate from pre-Java 7 annotation lists to repeatable annotations.

5. Conclusion

この記事では、すべてのJava開発者が精通している必要のあるJava組み込みアノテーションについて説明しました。

いつものように、記事のすべての例はGitHubにあります。