Edited at

いまさらJavaのアノテーションを復習する


概要

業務でSpring Bootを使うことになり、はるか昔の新卒のJava研修の内容しかなかった頭にアノテーションの概念をインプットする必要に迫られた。


参考にしたサイト

ものすごいわかりやすかったです

http://www.atmarkit.co.jp/ait/articles/1105/19/news127.html

特にこの例でスッと入ってきました


アノテーションとは、「注釈」という意味です。Javadocコメントは開発者に対してプログラムがどういうものかを説明するために使いましたが、これと同様に、コンパイラや実行環境に対してプログラムがどういうものかを伝えたいことがあります。

後述する具体的な例を見れば分かりますが、Javaではアノテーションをプログラムに記述することにより、コンパイラで出力される警告メッセージを抑制したり、実行環境によってプログラムの動作を変更したりできます。


実行時の利用についてはこちらを参考にさせていただきました。

https://www.qoosky.io/techs/390aad36f8


やってみる

java version 1.8.0_181

Java(TM) SE Runtime Environment (build 1.8.0_181-b13)

Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

src

└test

  └java

    └annotation

      ├ Main.java

      └ MethodInformation.java


内容

ただのマーカーとしてのアノテーション型を作って設定してみます。


MethodInformation.java

package test.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

// Targetアノテーションを付けることで「何につけられるアノテーションなのか?」を指定できる
@Target(ElementType.TYPE)
public @interface MethodInformation {
}



Main.java

package test.java.annotation;

@MethodInformation
public class Main {

public static void main(String[] args) {
System.out.println("Hello World!");
}
}


WS000060.JPG

WS000059.JPG


ElementType の種類って?

こちらをどうぞ



java.lang.annotation.ElementType.java

public enum ElementType {

/** Class, interface (including annotation type), or enum declaration */
TYPE,

/** Field declaration (includes enum constants) */
FIELD,

/** Method declaration */
METHOD,

/** Formal parameter declaration */
PARAMETER,

/** Constructor declaration */
CONSTRUCTOR,

/** Local variable declaration */
LOCAL_VARIABLE,

/** Annotation type declaration */
ANNOTATION_TYPE,

/** Package declaration */
PACKAGE,

/**
* Type parameter declaration
*
* @since 1.8
*/

TYPE_PARAMETER,

/**
* Use of a type
*
* @since 1.8
*/

TYPE_USE
}




実行

何の問題もなく出力されています。特に何もしないアノテーションなので出力内容に変更はありません。

WS000061.JPG

WS000062.JPG


メソッドにしか付けられないアノテーションにしてみる


MethodInformation.java

package test.java.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // メソッドにしか付けられません
public @interface MethodInformation {
}


不穏な空気です

WS000065.JPG


実行

無事失敗します

WS000066.JPG

WS000067.JPG


クラス内部からアノテーションの情報を取得する


MethodInformation.java

package test.java.annotation;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) // コンパイル→実行時にもアノテーションの情報を保持しておく必要がある
public @interface MethodInformation {
}



Main.java

package test.java.annotation;

@MethodInformation
public class Main {

public static void main(String[] args) {
Main mainInstance = new Main();
Class clazz = mainInstance.getClass();

// Mainクラスに設定されているアノテーションの種類を得る
System.out.println(clazz.getAnnotation(MethodInformation.class));
System.out.println("Hello World!");
}
}


WS000000.JPG

WS000002.JPG


RetentionPolicyの種類って?

こちらをどうぞ



java.lang.annotation.RetentionPolicy.java

public enum RetentionPolicy {

/**
* Annotations are to be discarded by the compiler.
*/

SOURCE,

/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/

CLASS,

/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/

RUNTIME
}




実行結果

@test.java.annotation.MethodInformation() が出力されてるのがわかります

WS000001.JPG


値が設定されたアノテーションの値を取得

アノテーション要素と呼ばれるものを作って、その値を取得してみる


MethodInformation.java

package test.java.annotation;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInformation {
String testString();
int testInt();
}



Main.java

package test.java.annotation;

@MethodInformation(testString = "this is test", testInt = 12345)
public class Main {

public static void main(String[] args) {
Main mainInstance = new Main();
Class clazz = mainInstance.getClass();

MethodInformation methodInformation = (MethodInformation)clazz.getAnnotation(MethodInformation.class);

// アノテーション型内ではメソッドで定義されている
System.out.println(methodInformation.testString());
System.out.println(methodInformation.testInt());
System.out.println("Hello World!");
}
}


WS000003.JPG

WS000005.JPG


実行結果

無事設定された値が見れました

WS000006.JPG


自分自身をアノテーションしても大丈夫


MethodInformation.java

package test.java.annotation;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MethodInformation(testString = "this is test double", testInt = 1234512345) // 自分自身をアノテーション
public @interface MethodInformation {
String testString() default "test";
int testInt() default 1234;
}



Main.java

package test.java.annotation;

@MethodInformation
public class Main {

public static void main(String[] args) {
Main mainInstance = new Main();
Class clazz = mainInstance.getClass();

MethodInformation methodInformation = (MethodInformation)clazz.getAnnotation(MethodInformation.class);

System.out.println(methodInformation.testString());
System.out.println(methodInformation.testInt());
System.out.println("Hello World!");
}
}


annotation_5.JPG

main_11.JPG


実行結果

上書きはされてない(アノテーションのデフォルト値が入っている)のが確認できる。少し不思議な気もします。

WS000000.JPG