Quantcast
Channel: Clouder::Blogger
Viewing all articles
Browse latest Browse all 18

Annotation basics in Java

$
0
0

アノテーション

最近、Javaを書いてます。(そんなに書いてないけど…)

で、Javaにはアノテーションという機能(?)がありますよね。
実際自分もいろんなところで使ってはいるんですが、ちゃんと理解しているわけじゃなかったので調べてみました。

アノテーションとは

アノテーションとはJava SE 5で追加された機能でクラスやメソッド、パッケージに対してメタデータとして付加情報を記入する機能です。

簡単にいうとクラスやメソッド、パッケージに様々な意味をもたせることが出来るということのようです。

publicclassSampleClass{@FooAnnotation// ←これとかpublicStringtext;@BarAnnotation("foo bar")// ←これとかpublicAnnotationSample(){//...}@BazAnnotation({"foo","bar"})// ←これとかpublicvoidsomeMethod(){//...}}

アノテーションの種類

Javaのアノテーションは主に以下のようなものがあります。

  • アノテーションが持つ値による分類
    • マーカーアノテーション
      値を持たず、名前だけを持つアノテーション
      例:@Deprecated, @Override
    • 単一値アノテーション
      値を1個だけ持つアノテーション
      例:@SuppressWarnings("unused")
    • フルアノテーション
      値を複数個持つアノテーション
      例:@Target({ ElementType.METHOD, ElementType.CLASS })
  • その他
    • メタアノテーション
      アノテーションに付与するアノテーション

アノテーションを自作する

アノテーションは自作することもできます。
作成するには@interfaceを使用します。

先にご紹介した各アノテーションを自作してみます。

マーカーアノテーション

マーカーアノテーションの作成は簡単です。
以下のようにするだけで終わりです。

public@interfaceSampleAnnotation{}

使用するには以下のようにするだけです。

@SampleAnnotation// ←これpublicclassSomeClass{//...}

単一値アノテーション

次に単一値アノテーションを作成してみます。

String型のvalue()というのを定義すればいいみたいです。

public@interfaceOneValueAnnotation{Stringvalue();}

使用方法としては、以下のようになります。
引数で値を渡すことができます。

@OneValueAnnotation("foo bar baz")// ←これpublicclassSomeClass{//...}

あと単一値アノテーションは、デフォルト値を設定することもできます。
デフォルト値を設定するには以下のように宣言のあとにdefault "value"と付け加えます。

public@interfaceOneValueAnnotation{Stringvalue()default"foo";}

こうすることで、値を書かない場合はdefaultで設定した値がセットされるようです。

フルアノテーション

フルアノテーションの場合は、以下のように2個以上の値を保持できるようにします。

public@interfaceFullAnnotation{Stringvalue1();Stringvalue2()default"foo";}

このアノテーションを使用する場合は以下のように名前を指定して値を渡します。

@FulAnnotation(value1="foo",value2="bar")publicclassSomeClass{//...}

メタアノテーション

メタアノテーションとは、アノテーションに付与するためのアノテーションです。
アノテーションに対してなにかの情報を付与することからアノテーションのアノテーションということでメタアノテーションと呼ばれます。

後述する@Target@Retentionもメタアノテーションです。

メタアノテーションは、以下のように@Targetを使用してアノテーションにのみ付与できるように定義します。

@Target(ElementType.ANNOTATION_TYPE)public@interfaceMetaAnnotation{}

@TargetElementType.ANNOTATION_TYPEを指定することで、アノテーションにのみ使用するように制限します。

使い方は以下のようになります。

@MetaAnnotationpublic@interfaceNewAnnotation{}

もしアノテーション以外のところで指定すると以下のようなエラーになります。

エラー: 注釈型はこの種類の宣言に使用できません

アノテーションの使用箇所の制限

アノテーションは、使用できる箇所を制限することができます。

制限をするには、先のメタアノテーションで軽く説明した@Targetというアノテーションを使用します。使用できる箇所は、ElementTypeというEnumに定義されています。

タイプ名使用できる箇所
ANNOTATION_TYPEアノテーション型の宣言
CONSTRUCTORコンストラクタの宣言
FIELDフィールドの宣言(enum定数を含む)
LOCAL_VARIABLEローカル変数の宣言
METHODメソッドの宣言
PACKAGEパッケージの宣言
PARAMETERメソッドのパラメータの宣言
TYPEクラス・インタフェース・enum・アノテーションの宣言
TYPE_PARAMETER型パラメータの宣言
TYPE_USE型使用箇所

この中でよく使うのは、CONSTRUCTOR, FIELD, METHODあたりでしょうか。

指定方法としては以下のようにすればOKです。

@Target(ElementType.METHOD)public@interfaceSampleAnnotation{}

複数指定することもできます。

@Target({ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.FIELD})public@interfaceSampleAnnotation{}

なお、@TargetMETHODだけを指定したアノテーションをメソッド以外のところで指定したら以下のようなエラーになりました。

エラー: 注釈型はこの種類の宣言に使用できません

アノテーションの値の保持期間

値の保持期間は@Retentionというアノテーションで指定します。

指定できる値はRetentionPolicyというEnum型に定義があります。具体的には以下。

タイプ保持期間
CLASSコンパイル時にクラスファイルに保持されますが、実行時にVMには保持されません。
RUNTIMEコンパイル時にクラスファイルに保持され、さらに実行時にVMにも保持されます。
リフレクションを使って値を取り出せます。
SOURCEソースファイルには保持されるが、コンパイルされたクラスファイルには保持されない。

値を実行時にも使いたい場合にはRUNTIMEが良いようですね。

指定方法としては以下のような感じ。

@Retention(RetentionPolicy.RUNTIME)public@interfaceSampleAnnotation{}

アノテーションで保持した値を参照する

アノテーションで保持した値を参照するには、以下のようにするとできます。

publicclassSampleClass{@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public@interfaceSampleAnnotation{Stringvalue()default"Default value";}@SampleAnnotation("Passed value")publicStringgetAnnotationValue()throwsNoSuchMethodException{Methodmethod=SampleClass.class.getDeclaredMethod("getAnnotationValue");SampleAnnotationsampleAnnotation=method.getDeclaredAnnotation(SampleAnnotation.class);returnsampleAnnotation.value();}publicstaticvoidmain(String[]args){try{SampleClasssampleClass=newSampleClass();System.out.println(sampleClass.getAnnotationValue());}catch(Exceptione){e.printStackTrace();}}}

@RetentionRetentionPolicy.RUNTIMEを指定していますが、これをRetentionPolicy.CLASSRetentionPolicy.SOURCEにすると実行時にExceptionが吐かれます。

このコードでは、実行時に値を参照できないといけないのでRetentionPolicy.RUNTIME以外を指定するとエラーになります。

アノテーションに設定した値はgetAnnotationValue()の中で取得しています。

その他のアノテーションの設定

上記の@Target@Retention以外にもアノテーションの挙動を設定するためのアノテーションがあります。

名前用途
@Documentedアノテーションを公開APIの一部としたい場合に使用。
簡単に言うと、javadocなどで作成されたドキュメントに指定されたアノテーションが載ります。
@Inheritedこれを指定されたアノテーションを使用したクラスのサブクラスにも継承したい場合に使用。

おわり

ということで、アノテーションについての基本的なことを勉強がてらまとめてみました。

とりあえずアノテーションがどんなものかわかったので、次はもうちょっと実用性のあるアノテーションを作るにはどうしたらいいのかとか、標準であるアノテーションがどんなものがあるのかなどを調べてみます。


Viewing all articles
Browse latest Browse all 18

Trending Articles