JAVA

最終更新日: 2023.02.16 (公開: 2022.12.19)

Javaの「アノテーション」はミス予防に便利!使い方や作成方法を紹介

Javaの「アノテーション」はミス予防に便利!使い方や作成方法を紹介

Javaの「アノテーション」は、ソースコードに「注釈」をつけるための機能です。アノテーションを活用することで、誤った記述・好ましくない記述に対してコンパイルエラーや警告が出せます。結果的に、より安全で効率的なプログラムが書きやすくなります。

しかし、アノテーションは必ずしも使わないといけない機能ではないので、「馴染みがない」「どんな機能かわからない」という人も多いはず。アノテーションにはさまざまな種類があり、自分でオリジナルのアノテーションも作成できるので、非常に便利な機能です。

そこで本記事では、Javaのアノテーションの使い方や作成方法、具体的な活用テクニックなどについて解説します。アノテーションに慣れていない人は、ぜひ参考にしてください。

Javaの「アノテーション」とは?注釈を付け加える機能

Javaの「アノテーション」とは、ソースコードに付け加える「注釈」のことです。「@」から始まるラベルのようなもので、クラス・インターフェース・フィールド・メソッドなどの「宣言の先頭」につけます。アノテーションの代表例は以下のようなものです。

@Override // 「Override」アノテーション
public void method() {
  // 以下略
}

アノテーションは、プログラムのロジックそのものとは直接関係がない、「情報」や「説明」を明示できる機能です。なお、注釈というと「コメント」を思い浮かべるかもしれませんが、コメントには「そのとおりに書きなさい」という強制力はいっさいありません。

アノテーションでは、クラスやメソッドの名前を間違えたときや、好ましくない書き方をしたときに「コンパイルエラー」や「警告」を出せます。その結果、正確なプログラムを書きやすくなるため、効率を重視する実務では積極的に活用されています。

アノテーションの大きなメリットは「ミスを予防できる」こと

アノテーションを使うことで得られる最も大きなメリットは、プログラミングのミスを予防できることです。プログラミングでは、ミスが多々発生します。コンパイルエラーが出るミスなら問題ありませんが、構文上の誤りがない場合はコンパイルが通り、実行時に思わぬエラーやバグの原因になることがあります。

アノテーションを活用すると、記述ミスや好ましくないソースコードに対して、エラーや警告を出力できるので、バグやエラーを予防可能です。また、アノテーションではコードの書き方を制限できるため、複数人で開発する現場で「意思統一」を図りやすくなります。ソースコード上でコミュニケーションが取れるので、開発効率が向上します。

Javaの基本的なアノテーションは5種類

Javaのアノテーションには、さまざまな種類があります。しかし、一般的に使われる「標準アノテーション」は、以下5種類しかありません。本章では、それぞれの機能と具体的な使い方を、サンプルコードを交えて解説します。

アノテーション 概要
@Override スーパークラスのメソッドをオーバーライドすることを宣言する
@Deprecated クラスやメソッドが「非推奨」であることを宣言する
@SuppressWarnings コンパイラの不要な警告を抑制する
@SafeVarargs 可変長引数のデータ型の安全性を保障する
@FunctionalInterface 関数型インターフェースとして定義することを宣言する

@Override

「@Override」は、「スーパークラスのメソッドをオーバーライドする」ことを示すアノテーションです。対象となるメソッドが、スーパークラスのメソッドをオーバーライドしていることを保障し、正しくオーバーライドできていない場合はコンパイルエラーとなります。@Overrideアノテーションの使い方を、以下のサンプルコードで確認しましょう。

//サンプルプログラム

class SuperClass {

  public void method(String string) {
    System.out.println("スーパークラスのメソッド" + string);
  }

}

class SubClass extends SuperClass {

  // 「Override」アノテーションを活用し、
  // スーパークラスのメソッドをオーバーライドしたことを宣言する
  @Override
  public void method(String string) {
    System.out.println("基底クラスのメソッド" + string);
  }

}

public class Main {

  public static void main(String[] args) {
    // サブクラスをインスタンス化する
    SubClass sub = new SubClass();

    // サブクラスの「method」を実行する
    sub.method("テスト");
  }

}

//実行結果

基底クラスのメソッドテスト

アクセス修飾子・戻り値の型・メソッド名・引数など、どれかひとつでも間違っている場合はコンパイルエラーとなるため、対象メソッドを確実にオーバーライドできます。なお、オーバーライドではないメソッドに「@Override」アノテーションを付けた場合も、コンパイルエラーとなります。

@Deprecated

「@Deprecated」は、「クラスやメソッドが非推奨である」ことを示すアノテーションです。たとえば大規模プロジェクトの場合は、処理内容が好ましくないクラス・メソッドがあるものの、互換性のために残すことがあります。しかし、「どうしても必要なとき以外は使ってほしくない」という場合、@Deprecatedアノテーションが役立ちます。

// クラスを「非推奨」にする
@Deprecated(since="バージョン") // 「バージョン」には数値を指定する
class Test {
  // 以下略
}

// メソッドを「非推奨」にする
@Deprecated(since="バージョン") // 「バージョン」には数値を指定する
public void method() {
  // 以下略
}

@Deprecatedアノテーションは、コンパイルエラーではなく警告を出すので、ほかのプログラマーに代替のクラスやメソッドの使用を促すことができます。@Deprecatedアノテーションの使い方を、以下のサンプルコードで確認しましょう。

//サンプルプログラム

// クラスを「非推奨」にする
@Deprecated(since = "8")
class Test {

  // メソッドを「非推奨」にする
  @Deprecated(since = "9")
  public void method() {
    System.out.println("非推奨のメソッド実行");
  }

}

public class Main {

  public static void main(String[] args) {
    // テストクラスをインスタンス化する
    Test test = new Test();

    // テストクラスの「method」を実行する
    test.method();
  }

}

//実行結果
非推奨のメソッド実行

以上のように、@Deprecatedアノテーションが付与されたクラスやメソッドを使っても、コンパイルエラーは出ず通常どおり実行できます。ただし、非推奨であることを示す警告が表示されるため、プログラマー同士のコミュニケーションに効果的です。

なお「Eclipse」をIDEとして使っている場合は、@Deprecatedアノテーションが付与されているクラスやメソッドに、上記画像のような「打ち消し線」が表示されます。そのため、ほかのプログラマーが見ても明らかに「非推奨」だとわかり、クラスやメソッドの使用を抑制できます。

@SuppressWarnings

「@SuppressWarnings」は、「コンパイラの不要な警告を抑制する」ためのアノテーションです。Javaのコンパイラは、安全なプログラミングをサポートするために、さまざまな警告を出します。しかし、コンパイラが不要な警告を出すときや、意図して警告が出るようなコードを書いているときなどは、こうした警告は邪魔になってしまいます。

余計な警告は無視するものですが、それが多すぎると「本当に重要な警告」を見逃してしまいかねません。@SuppressWarningsアノテーションを使うことで、重要な警告に注目しやすくなります。@SuppressWarningsアノテーションは以下のように使います。

@SuppressWarnings("警告名") // 「警告名」には後述する既定値を指定する
// 以下、警告対象のメソッドやクラス

たとえば、メソッドに未使用のローカル変数がある場合は、コンパイラは「ローカル変数が使用されていません」という警告を表示します。しかし、将来的にメソッドを拡張するために、あえて未使用の変数を残すケースは多いです。そこで以下のサンプルコードのように、@SuppressWarningsアノテーションを活用して、余計な警告を抑制しましょう。

//サンプルプログラム

class Test {

  public void method() {
    // 変数「i」は未使用だが、将来的な拡張のために残しておきたい。
    // しかし、そのままでは不要な警告が出るので、
    // 「@SuppressWarnings("unused")」で「未使用変数」の警告を抑制する。
    @SuppressWarnings("unused")
    int i;
  }

}

public class Main {

  public static void main(String[] args) {
    // テストクラスをインスタンス化する
    Test test = new Test();

    // テストクラスの「method」を実行する
    test.method();
  }

}

//実行結果
以下の画像のように、「int i;」の部分に警告が表示されなくなります。

Eclipseの場合は、警告が出た部分はコードエディター上で「波線」が表示されます。未使用変数の警告名は「unused」なので、今回は「@SuppressWarnings(“unused”)」と記述すればOK。ちなみに、主な警告名には以下のようなものがあります。

警告名 意味 アノテーション
cast 不要なキャストを行っている @SuppressWarnings(“cast”)
deprecation 非推奨のクラスやメソッドを使用している @SuppressWarnings(“deprecation”)
finally finallyブロックの処理が正常に実行されない @SuppressWarnings(“finally”)
null ヌルポインターへのアクセスが行われた @SuppressWarnings(“null”)
unchecked 危険な可能性がある型キャストを行っている @SuppressWarnings(“unchecked”)
divzero ゼロ除算を行っている @SuppressWarnings(“divzero”)
unused 未使用のローカル変数がある @SuppressWarnings(“unused”)

ちなみに、警告名を個別に指定するのが面倒な場合は「@SuppressWarnings(“all”)」ですべての警告を抑制できますが、基本的には推奨しません。

@SuppressWarningsアノテーションは、あくまで「警告内容を理解したうえで、安全なプログラムを警告なしで書く」ためのものなので乱用はしないようにしましょう。またEclipseでは、不要な@SuppressWarningsアノテーションを書いた場合は、警告が出てしまいます。

@SafeVarargs

「@SafeVarargs」は、「可変長引数のデータ型の安全性を保障する」ためのアノテーションです。可変長引数とは、メソッドが任意の数(0個以上)の引数を取ることができる機能。「呼び出し元がどれくらいデータを引き渡すかわからない」場合でも、柔軟なプログラミングができるので便利です。

しかし可変長引数の実態は「配列」なので、可変長引数がジェネリクス付きの場合は、メソッド内で安全な操作が行われてしまうことがあります。たとえば、可変長引数を「Object型配列」に変換して、危険な型キャストを行うなどです。

そのため、可変長引数がジェネリクス付きの場合は、その危険性を示すために「潜在的なヒープ汚染」警告が表示されます。しかし、確実に安全なソースコードを書いている場合は邪魔な警告なので、以下のサンプルコードのように「@SafeVarargs」で警告を抑制するのがおすすめです。

//サンプルプログラム

import java.util.Arrays;
import java.util.List;

public class Main {

  public static void main(String[] args) {
    // リスト形式に変換した文字列を、文字列として表示する
    for (String str : toList("A", "B", "C", "D", "E")) {
      System.out.println(str);
    }

  }
  
  // 可変長引数の警告を抑制するために「@SafeVarargsアノテーション」を付与する
  @SafeVarargs
  public static  List toList(T... args) {
    // 可変長引数の文字列をリスト形式に変換する
    return Arrays.asList(args);
  }
  
}

//実行結果
A
B
C
D
E

==============================

なお、@SafeVarargsアノテーションを使用しない場合、以下の画像のように警告が表示されます。

@SafeVarargsアノテーションを付与することで、警告が表示されなくなります。

以上のように、「@SafeVarargsアノテーション」を付けると余計な警告を抑制できます。ただし、@SafeVarargsアノテーションはメソッドが「final」もしくは「static」でなければ使えません。これは、オーバーライドされたメソッドでは、安全性を保障できないことが理由だと考えられます。

@FunctionalInterface

「@FunctionalInterface」は、インターフェースが「関数型インターフェース」であることを定義するためのアノテーションです。関数インターフェースは、ラムダ式やメソッド参照に使用できる便利な機能です。

ただし関数インターフェースは、「定義されている抽象メソッドがひとつだけ」で「実装されているメソッドがひとつもない」という条件を満たさなければ、関数インターフェースとして機能しません。そのため、関数インターフェースの定義にミスがあると、思わぬバグやエラーの原因になることがあります。

そこで便利なのが、@FunctionalInterfaceアノテーションです。対象となる関数インターフェースに付与することで、定義ミスがある場合にコンパイルエラーが出るようになります。以下のサンプルコードで詳細を確認しましょう。

//サンプルプログラム

// 関数型インターフェースであることを明示するために
// 「@FunctionalInterfaceアノテーション」を付与する
@FunctionalInterface
interface TestInterface {
  public void method();
}

class TestClass implements TestInterface {
  public void method() {
    System.out.println("関数型インターフェースのメソッド実行");
  }
}

public class Main {

  public static void main(String[] args) {
    // TestClassのインスタンスを生成する
    TestClass test = new TestClass();
    
    // TestClassのmethodを実行する
    test.method();
  }
}

//実行結果

関数型インターフェースのメソッド実行

以上のように、@FunctionalInterfaceアノテーションを付与することで、対象となるインターフェースが「関数インターフェース」であることを保障できます。なお、条件を満たさない関数インターフェースに@FunctionalInterfaceアノテーションを付与すると、以下のようにコンパイルエラーとなります。

// このクラスには抽象メソッドが複数あるため、
// 「関数インターフェース」の条件を満たしておらず、
// 「@FunctionalInterfaceアノテーション」を付与するとエラーになる
@FunctionalInterface
interface TestInterface {
public void methodA();
public void methodB();
public void methodC();
}

「自作アノテーション」の作成方法・使い方を解説

Javaの標準機能として利用できるアノテーションは、基本的には前述した「@Override」「@Deprecated」「@SuppressWarnings」「@SafeVarargs」「@FunctionalInterface」の5種類のみです。

一方で、Javaのアノテーションは自作することもできます。「自作アノテーション」を活用すれば、さらにわかりやすい注釈をソースコードに付与できるので便利です。ここからは、自作アノテーションの作成方法・使い方を以下5つのステップから解説します。

  • アノテーションを定義する
  • メタアノテーションを追加する
  • アノテーションで注釈を付与する
  • アノテーション情報を取得する
  • アノテーションを活用する

ステップ1:アノテーションを定義する

まずはアノテーション本体を定義します。自作アノテーションは、以下の構文で定義できますが、通常のクラスやインターフェース、メソッドとは異なるので注意してください。

@interface アノテーション名 {

  // 規定値を設定しない場合
  型名 要素名();

  // 規定値を設定する場合
  型名 要素名() default 既定値;

}

慣れるまでわかりにくいかもしれませんが、自作アノテーションは「@interface」の後ろに「アノテーション名」を記述すると定義できるでしょう。アノテーション内部では、アノテーションとして付与できる要素を指定し、必要に応じて規定値も指定できます。

なお、すべてのアノテーションは「java.lang.annotation.Annotation」を継承していますが、アノテーション定義に「extends」は不要です。以下のサンプルは、「作成者」「種類」「詳細説明」の情報を付与できるアノテーションになります。

// アノテーション本体を定義する
@interface Annotation {

  // アノテーションを付与した要素の作成者
  // 今回は「default」で規定値を「コードカキタイ」とする
  String author() default "コードカキタイ";

  // アノテーションを付与する要素の種類
  String type();

  // アノテーションを付与する要素の詳細説明
  String description();

}

ステップ2:メタアノテーションを追加する

次に「メタアノテーション」を追加します。メタアノテーションは「java.lang.annotation」パッケージで提供される機能で、自作アノテーションの「適用範囲」や「保持期限」など、アノテーションの性質を決めるためのものです。メタアノテーションには、大きく分けて以下4種類のものがあります。

メタアノテーション 概要 指定方法(詳細後述)
@Documented 付与したアノテーションを「JavaDoc」に含めるかどうか ソースコードに「@Documented」と記載すれば、「JavaDoc」に含まれるようになる
@Target アノテーションをどの要素に付与できるか 「java.lang.annotation.ElementType」の値から選択する
@Retention アノテーション情報がどの段階まで保存されるか 「java.lang.annotation.RetentionPolicy」の値から選択する
@Inherited サブクラスにも同じアノテーションが継承されるか ソースコードに「@Inherited」と記載すれば、サブクラスに継承されるようになる

「@Documented」と「@Inherited」については、以下のようにソースコード中にそのまま記載すれば機能が有効化されます。なお、「@Documented」に関連する「JavaDoc」については、後ほど改めて解説します。

// 作成・付与した自作アノテーションを「JavaDoc」に含める
@Documented

// スーパークラスに付与したアノテーションを、サブクラスが継承するようにする
@Inherited

「@Inherited」は、サブクラスにアノテーションを付与していないとき、自動的にスーパークラスに付与したアノテーションが適用される機能です。ただし、クラスに付与した場合のみ有効で、フィールドやメソッドのアノテーションは継承されません。

「@Target」と「@Retention」は、それぞれパッケージで規定された値から選択します。@Targetの代表的な値は以下のとおりです。

@Targetに指定できる値 概要
ElementType.TYPE クラス・インターフェース・アノテーション・enum型に対して、アノテーションを付与できる
ElementType.FIELD フィールドに対して、アノテーションを付与できる
ElementType.CONSTRUCTOR コンストラクタに対して、アノテーションを付与できる
ElementType.METHOD メソッドに対して、アノテーションを付与できる

アノテーションはさまざまな要素に付与するため、基本的には上記4つのすべてを指定しておくと便利です。以下のように、「@Target({指定する値})」という構文で値を指定しましょう。

// 自作アノテーションの「Target」を定義する
// クラス(TYPE)・フィールド(FIELD)・コンストラクタ(CONSTRUCTOR)・メソッド(METHOD)
// 4種類いずれの要素に対して、アノテーションを付与できるか指定する
@Target({
    ElementType.TYPE,
    ElementType.FIELD,
    ElementType.CONSTRUCTOR,
    ElementType.METHOD
})

@Retentionに指定できる値は、以下3種類に限られています。

@Retentionに指定できる値 概要
RetentionPolicy.SOURCE アノテーション情報は、ソースコードの段階まで保持されるが、コンパイル時に破棄される
RetentionPolicy.CLASS アノテーション情報はコンパイルの段階まで保持されるが、実行時に、JVM(Java仮想マシン)に破棄される
RetentionPolicy.RUNTIME アノテーション情報はJVM(Java仮想マシン)に保持されるため、実行中にアノテーション情報を取得できる

ほとんどの場合は、以下のように「RetentionPolicy.RUNTIME」を指定するので、定型文として覚えておくといいでしょう。

// 自作アノテーションの「Retention」を定義する
// アノテーション情報をどの段階まで保持するか指定する
// 「SOURCE」はソースコードの段階まで
// 「CLASS」はコンパイルが行われるときまで
// 「RUNTIME」は実行中もアノテーション情報を保持する
@Retention(RetentionPolicy.RUNTIME)

メタアノテーションについて知っておくべき知識は以上のとおりです。ただし、メタアノテーションを指定する際は、値を定義しておくパッケージをimportする必要があります。その部分も含めて、メタアノテーションの定義方法を再確認しておきましょう。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 作成・付与した自作アノテーションを「JavaDoc」に含める
@Documented

// 自作アノテーションの「Target」を定義する
// クラス(TYPE)・フィールド(FIELD)・コンストラクタ(CONSTRUCTOR)・メソッド(METHOD)
// 4種類いずれの要素に対して、アノテーションを付与できるか指定する
@Target({
    ElementType.TYPE,
    ElementType.FIELD,
    ElementType.CONSTRUCTOR,
    ElementType.METHOD
})

// 自作アノテーションの「Retention」を定義する
// アノテーション情報をどの段階まで保持するか指定する
// 「SOURCE」はソースコードの段階まで
// 「CLASS」はコンパイルが行われるときまで
// 「RUNTIME」は実行中もアノテーション情報を保持する
@Retention(RetentionPolicy.RUNTIME)

// スーパークラスに付与したアノテーションを、サブクラスが継承するようにする
@Inherited

ステップ3:アノテーションで注釈を付与する

先ほどの手順で、自作アノテーションの定義自体は完了です。あとは以下のサンプルコードのように、実際にクラスやフィールド、メソッドなどにアノテーションを付与しましょう。

// クラスにアノテーションを付与する
@Annotation(type = "クラス", description = "テスト用クラス")
class Test {

  // フィールドにアノテーションを付与する
  @Annotation(author = "サンプルコード担当者", type = "フィールド", description = "テスト用フィールド")
  private int i = 0;

  // コンストラクタにアノテーションを付与する
  @Annotation(type = "コンストラクタ", description = "テスト用クラスのコンストラクタ")
  public Test() {
    System.out.println("Testクラスのコンストラクタ");
  }

  // メソッドにアノテーションを付与する
  @Annotation(author = "サンプルコード担当者", type = "メソッド", description = "テスト用メソッド")
  public void method() {
    System.out.println("Testクラスで自作アノテーションを使用!");
  }

}

上記のサンプルコードでは、クラス・フィールド・コンストラクタ・メソッドにアノテーションを付与しています。ただし、「@Target」で値を正しく設定していない場合は、一部の要素にしかアノテーションを付与できないので要注意。

アノテーションの付与方法がわかりづらいかもしれませんが、要はメソッドに引数を引き渡すときのように、「@アノテーション名(各要素に値を代入)」という形式で記載すればOKです。デフォルト値を設定している場合を除き、すべての要素を記載する必要があります。

ステップ4:アノテーション情報を取得する

付与したアノテーション情報は、「java.lang.reflectパッケージ」の「リフレクション機能」を活用することで、プログラム実行中に取得できます。ただし「@Retention」に「RetentionPolicy.RUNTIME」を指定していなければ、この機能は使えないので要注意。アノテーション情報の取得方法は、以下のサンプルコードのとおりです。

public class Main {

  public static void main(String args[]) throws Exception {
    // アノテーションを付与したクラスのインスタンスを生成する
    Test test = new Test();

    // テストクラスのメソッドを実行する
    test.method();

    // クラス情報を取得する
    Class<?> classInfo = test.getClass();

    // クラスに付与したアノテーションを取得する
    Annotation classAnnotation = classInfo.getAnnotation(Annotation.class);

    // フィールドに付与したアノテーションを取得する
    Field fieldInfo = classInfo.getDeclaredField("i");
    Annotation fieldAnnotation = fieldInfo.getAnnotation(Annotation.class);

    // コンストラクタに付与したアノテーションを取得する
    Constructor<?> constructorInfo = classInfo.getConstructor();
    Annotation constructorAnnotation = constructorInfo.getAnnotation(Annotation.class);

    // メソッドに付与したアノテーションを取得する
    Method methodInfo = classInfo.getMethod("method");
    Annotation methodAnnotation = methodInfo.getAnnotation(Annotation.class);
  }

}

複雑なプログラムになりましたが、重要なポイントはまず「Class<?>オブジェクト」に、アノテーションを付与したクラスの情報を取得することです。そのうえで、「getAnnotationメソッド」でアノテーションの種類を指定すると、「Annotationオブジェクト」にアノテーション情報が格納されます。

アノテーション情報の取得方法は、どのプログラムでも基本的には同じなので、「定型文」として覚えておくといいでしょう。なお、取得したアノテーション情報の扱い方については後述します。

ステップ5:アノテーションを活用する

これまでご紹介したステップを踏まえて、アノテーション情報の定義・付与・取得すべてを行うサンプルプログラムをご紹介します。

//サンプルプログラム

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 作成・付与した自作アノテーションを「JavaDoc」に含める
@Documented

// 自作アノテーションの「Target」を定義する
// クラス(TYPE)・フィールド(FIELD)・コンストラクタ(CONSTRUCTOR)・メソッド(METHOD)
// 4種類いずれの要素に対して、アノテーションを付与できるか指定する
@Target({
    ElementType.TYPE,
    ElementType.FIELD,
    ElementType.CONSTRUCTOR,
    ElementType.METHOD
})

// 自作アノテーションの「Retention」を定義する
// アノテーション情報をどの段階まで保持するか指定する
// 「SOURCE」はソースコードの段階まで
// 「CLASS」はコンパイルが行われるときまで
// 「RUNTIME」は実行中もアノテーション情報を保持する
@Retention(RetentionPolicy.RUNTIME)

// スーパークラスに付与したアノテーションを、サブクラスが継承するようにする
@Inherited

// アノテーション本体を定義する
@interface Annotation {

  // アノテーションを付与した要素の作成者
  // 今回は「default」で規定値を「コードカキタイ」とする
  String author() default "コードカキタイ";

  // アノテーションを付与する要素の種類
  String type();

  // アノテーションを付与する要素の詳細説明
  String description();

}

// クラスにアノテーションを付与する
@Annotation(type = "クラス", description = "テスト用クラス")
class Test {

  // フィールドにアノテーションを付与する
  @Annotation(author = "サンプルコード担当者", type = "フィールド", description = "テスト用フィールド")
  private int i = 0;

  // コンストラクタにアノテーションを付与する
  @Annotation(type = "コンストラクタ", description = "テスト用クラスのコンストラクタ")
  public Test() {
    System.out.println("Testクラスのコンストラクタ");
  }

  // メソッドにアノテーションを付与する
  @Annotation(author = "サンプルコード担当者", type = "メソッド", description = "テスト用メソッド")
  public void method() {
    System.out.println("Testクラスで自作アノテーションを使用!");
  }

}

public class Main {

  public static void main(String args[]) throws Exception {
    // アノテーションを付与したクラスのインスタンスを生成する
    Test test = new Test();

    // テストクラスのメソッドを実行する
    test.method();

    // クラス情報を取得する
    Class<?> classInfo = test.getClass();

    // クラスに付与したアノテーションを取得する
    Annotation classAnnotation = classInfo.getAnnotation(Annotation.class);

    // フィールドに付与したアノテーションを取得する
    Field fieldInfo = classInfo.getDeclaredField("i");
    Annotation fieldAnnotation = fieldInfo.getAnnotation(Annotation.class);

    // コンストラクタに付与したアノテーションを取得する
    Constructor<?> constructorInfo = classInfo.getConstructor();
    Annotation constructorAnnotation = constructorInfo.getAnnotation(Annotation.class);

    // メソッドに付与したアノテーションを取得する
    Method methodInfo = classInfo.getMethod("method");
    Annotation methodAnnotation = methodInfo.getAnnotation(Annotation.class);

    // 改行する
    System.out.println("");

    // クラスのアノテーションを表示する
    System.out.println("クラスのアノテーション");
    System.out.println("作成者:" + classAnnotation.author());
    System.out.println("種類:" + classAnnotation.type());
    System.out.println("詳細説明:" + classAnnotation.description());

    // 改行する
    System.out.println("");

    // フィールドのアノテーションを表示する
    System.out.println("フィールドのアノテーション");
    System.out.println("作成者:" + fieldAnnotation.author());
    System.out.println("種類:" + fieldAnnotation.type());
    System.out.println("詳細説明:" + fieldAnnotation.description());

    // 改行する
    System.out.println("");

    // コンストラクタのアノテーションを表示する
    System.out.println("コンストラクタのアノテーション");
    System.out.println("作成者:" + constructorAnnotation.author());
    System.out.println("種類:" + constructorAnnotation.type());
    System.out.println("詳細説明:" + constructorAnnotation.description());

    // 改行する
    System.out.println("");

    // メソッドのアノテーションを表示する
    System.out.println("メソッドのアノテーション");
    System.out.println("作成者:" + methodAnnotation.author());
    System.out.println("種類:" + methodAnnotation.type());
    System.out.println("詳細説明:" + methodAnnotation.description());
  }

}

//実行結果

Testクラスのコンストラクタ
Testクラスで自作アノテーションを使用!

クラスのアノテーション
作成者:コードカキタイ
種類:クラス
詳細説明:テスト用クラス

フィールドのアノテーション
作成者:サンプルコード担当者
種類:フィールド
詳細説明:テスト用フィールド

コンストラクタのアノテーション
作成者:コードカキタイ
種類:コンストラクタ
詳細説明:テスト用クラスのコンストラクタ

メソッドのアノテーション
作成者:サンプルコード担当者
種類:メソッド
詳細説明:テスト用メソッド

注目したいポイントは、mainメソッドでアノテーション情報を取得している部分です。まずは「Class<?> classInfo = test.getClass();」でクラス情報を取得。「<?>」の部分は「ワイルドカード」と呼ばれ、getClassメソッドの戻り値を受けるために必要です。

そのうえで、自作した「Annotation」クラスの変数を宣言。getAnnotationメソッドの引数で自作アノテーションクラスを指定し、クラス・フィールド・コンストラクタ・メソッドそれぞれに付与したアノテーション情報を取得します。

あとはprintlnメソッドで、自作アノテーションクラスの各要素を取り出せば、すべての情報を表示できます。複雑なプログラムではありますが、ほとんどの部分は「定型文」として使いまわせるので便利です。

Javaのアノテーションは「JavaDoc」の作成に便利!

これまでご紹介した方法で、Javaのソースコードにアノテーションを付与しておくと、「JavaDoc」をわかりやすく生成できます。そもそも「JavaDoc」とは、簡単に言うとJavaのソースコードの説明書です。まるでホームページのような見た目でわかりやすく、ソースコードから自動的に生成することができます。

ソースコードの構造や内容、コメントやアノテーション情報などが表示されるので、ぜひ活用したい機能です。ただし、メタアノテーションで「@Documented」を有効化しておかないと、JavaDocにアノテーション情報が掲載されないので要注意。JavaDocは、Eclipseを使用している場合は以下の手順で簡単に作成できます。

IDE上部のメニューから、「プロジェクト」→「JavaDocを生成」をクリックします。

JavaDoc生成のオプション画面が表示されます。基本的にはデフォルト設定でOKですが、「次の可視性を持つメンバーのJavaDocを作成」は、「Private」にしておくとすべての情報が出力されるのでおすすめ。「完了」をクリックすると、すぐにJavaDocが作成されます。

なお、多数の警告が表示されるかもしれませんが、ほとんどは「コメントなし」が原因なので気にしなくて構いません。JavaDocを作成したら、以下の手順でJavaDocを表示してみましょう。

左側の「パッケージエクスプローラー」で現在のファイル名を選択し、「ナビゲート」→「添付されたJavaDocを開く」をクリックすると、先ほど生成されたJavaDocが開きます。

このように、WebブラウザでホームページのようにJavaDocを閲覧できます。上部のタブからクラスを選択すると、先ほど作成した自作アノテーションクラスのドキュメントもチェックできます。

なおJavaDocでは、アノテーションを日本語で記述すると、Unicodeの16進数で表示されてしまいます。基本的にはこれを解決する方法はないので、気になる場合はアノテーションをすべて英語で記載しましょう。

Javaのアノテーションでソースコードを見やすくしよう!

Javaのアノテーションは、ソースコードの誤入力や抜け漏れを防ぎ、正確なプログラムを作成するための機能。好ましくないコードを書いたときに、コンパイラがエラーや警告を出すようにできるので便利です。

複雑な手順が必要ですが、自作アノテーションも作成すれば、標準機能では利用できないアノテーションを付与できます。クラスやメソッドに詳しいコメントを記載できますし、JavaDocに含めることもできるので、ぜひ活用してみましょう。

アクセスランキング 人気のある記事をピックアップ!

    コードカキタイがオススメする記事!

    1. 子供におすすめのプログラミングスクール10選!学習メリットや教室選びのコツも紹介

      2024.01.26

      子供におすすめのプログラミングスクール10選!学習メリットや教室選びのコツも紹介

      #プログラミングスクール

    2. 【完全版】大学生におすすめのプログラミングスクール13選!選ぶコツも詳しく解説

      2022.01.06

      【完全版】大学生におすすめのプログラミングスクール13選!選ぶコツも詳しく解説

      #プログラミングスクール

    3. 【未経験でも転職可】30代におすすめプログラミングスクール8選!

      2024.01.26

      【未経験でも転職可】30代におすすめプログラミングスクール8選!

      #プログラミングスクール

    4. 初心者必見!独学のJava学習方法とおすすめ本、アプリを詳しく解説

      2024.01.26

      初心者必見!独学のJava学習方法とおすすめ本、アプリを詳しく解説

      #JAVA

    5. 忙しい社会人におすすめプログラミングスクール15選!失敗しない選び方も詳しく解説

      2024.01.26

      忙しい社会人におすすめプログラミングスクール15選!失敗しない選び方も詳しく解説

      #プログラミングスクール

    1. 【無料あり】大阪のおすすめプログラミングスクール14選!スクール選びのコツも紹介

      2022.01.06

      【無料あり】大阪のおすすめプログラミングスクール14選!スクール選びのコツも紹介

      #プログラミングスクール

    2. 【目的別】東京のおすすめプログラミングスクール20選!スクール選びのコツも徹底解説

      2024.01.26

      【目的別】東京のおすすめプログラミングスクール20選!スクール選びのコツも徹底解説

      #プログラミングスクール

    3. 【無料あり】福岡のおすすめプログラミングスクール13選!選び方も詳しく解説

      2024.01.26

      【無料あり】福岡のおすすめプログラミングスクール13選!選び方も詳しく解説

      #プログラミングスクール

    4. 【徹底比較】名古屋のおすすめプログラミングスクール13選!選び方も詳しく解説

      2024.01.26

      【徹底比較】名古屋のおすすめプログラミングスクール13選!選び方も詳しく解説

      #プログラミングスクール

    5. 【徹底比較】おすすめのプログラミングスクール18選!失敗しない選び方も徹底解説

      2024.01.26

      【徹底比較】おすすめのプログラミングスクール18選!失敗しない選び方も徹底解説

      #プログラミングスクール