アノテーションについて調べると宣言してから大分経ちますが、やっと調べました。
アノテーションはコードに注釈を付ける機能で、コメントとかjavadocと同等の位置づけです。ただ、その注釈がプログラムから読める書式となってるのがポイントっぽいです。
例えば、Poolを提供するライブラリを作った時に、Poolをして欲しいクラスではEnablePoolアノテーションでコメントを付けておいてね、って決まりにしたりするわけです。以下のコードで三つのクラスを定義してますが、ClassAとClassBは、それぞれ10個か5個までプーリングされてもいい作りです、と注釈されています。
@EnablePool(10) class ClassA{ } @EnablePool(5) class ClassB{ } class ClassC{ }
で、Poolのライブラリ側はこのコメントを見て、クラスが望んでいる通りにプールしてあげるわけです。この機能自体は、例えばintafaceでPoolable#getMax()みたいなメソッドを提供させるってことでも実現は出来そうですが、アノテーションの良さは、このクラスの機能を全く汚さずに、目印だけ付けることができるってことだと思います。
または、アノテーションの代わりに外部にxmlでmappingを書くことでも実現出来そうです。これと比較した場合のアノテーションのメリットは、コードの近くに注釈を付けれるってことになるでしょうか? クラスが大きくなると、xmlとコードを対応させて把握していくのは非常にコストのかかる仕事になります。
で、このEnablePoolアノテーションですが、この定義は以下の通りです。
import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Retention; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @interface EnablePool{ int value(); }
アノテーションは@interfaceで宣言します*1。value()メソッドが、デフォルトの引数のgetterとなりますので、単一値のアノテーションの場合はこれを定義するといいようです。
このEnablePoolアノテーションの定義にも、アノテーションが施されています。@Retentionと@Targetがそれで、それぞれ、「注釈を実行時に参照出来るようにする」「この注釈は、型に対して付けるべき」であることを示しています。
最後に、EnablePoolアノテーションを利用する、Poolライブラリの実装です。
class Pool{ static final private Map<Class,List<Object>> pool = new HashMap<Class,List<Object>>(); static Object getInstance(Class<?> cls) { // アノテーション取得 EnablePool poolAnnotation = cls.getAnnotation(EnablePool.class); // アノテーションの有無を確認 if(poolAnnotation == null){ // アノテーションがない時は、そのままコンストラクタを呼ぶ(例外処理は略) return cls.newInstance(); } // アノテーションから数を取得 int maxPool = poolAnnotation.value(); Object obj = null; /* 以下、真面目にプールの処理を実装する */ return obj; } }
リフレクション系のAPIに、そのクラス・フィールド・メソッドに紐づくアノテーションを取得するメソッドが追加されていますので、それを利用してアノテーションを参照します。
この例ですと、Pool.getInstance(ClassA.class) 等と呼び出すと、このクラスに紐づいているアノテーションに基づいてpoolを利用しながらインスタンスを返します。
*1:@annotationとかの方がわかりやすかったのでは? 実装がinterfaceだからかしら?