2013-08-12 16 views
61

注釈はJavaで内部的にどのように動作するのですか?注釈は内部的にどのように動作するのですか

Javaでjava.lang.annotationライブラリを使用してカスタムアノテーションを作成する方法を知っています。しかし、私は@Overrideアノテーションのように内部的にどのように動いているのか十分な考えはまだありません。

誰かが詳細に説明すると本当に感謝します。

+2

あなたは「内部で働く」とはどういう意味ですか?コンパイラ?ランタイム? – chrylis

+0

@christis内部的には、このメソッドがオーバーライドメソッドであることが自動的に識別されるか、またはこのメソッドがオーバーライドメソッドではありません。それは両方の時間の仕事です。コンパイル時のアノテーションとスプリングのコントローラアノテーションのようなものは、実行時の作業です。 –

答えて

94

最初の主な違いは、コンパイル時に使用されてから廃棄されるか(たとえば@Override)、コンパイルされたクラスファイルに配置され、実行時に使用可能かどうかです(Springの@Componentなど)。これは、注釈のポリシーによって決定されます(@Retention)。独自のアノテーションを記述している場合は、アノテーションが実行時(おそらく自動設定用)に役立つのか、コンパイル時(チェックやコード生成用)に役立つのかを判断する必要があります。

注釈付きのコードをコンパイルするとき、コンパイラは、アクセス修飾子(public/private)またはfinalのように、ソース要素上に他の修飾子があるのと同じように注釈を見ます。アノテーションに遭遇すると、アノテーションプロセッサが実行されます。これは、プラグインクラスのように、特定のアノテーションに関心があると言います。注釈プロセッサは一般にReflection APIを使用してコンパイルされている要素を検査し、単純にチェックを実行したり、コンパイルしたり、コンパイルする新しいコードを生成することができます。 @Overrideが最初の例です。 Reflection APIを使用して、スーパークラスのいずれかのメソッドシグネチャに一致するものが見つかるかどうかを確認し、一致しない場合はMessagerを使用してコンパイルエラーを発生させます。

アノテーションプロセッサの作成には多数のチュートリアルが用意されています。 here's a useful one。コンパイラがどのように注釈プロセッサを呼び出すかについては、the Processor interfaceのメソッドを見てください。主操作はprocessメソッドで行われ、コンパイラが一致する注釈を持つ要素を見るたびに呼び出されます。

+0

ありがとうございます。@chrylis今、私はAnnotationに関するすべての疑問を明確にしています。 –

+2

Springの注釈プロセッサが@Componentを解析し、そのコンテナにそのクラスを注入する方法をちゃんと指摘するといいでしょう。 –

+0

@shanyangquこれは、Spring固有の問題ではない話題です。あなたは自分でポストプロセッサーのクラスを読むことができます。 – chrylis

5

ここには@Overridehttp://www.docjar.com/html/api/java/lang/Override.java.htmlです。

あなた自身で書く可能性のある注釈と区別するために特別なことは何もありません。興味深いビットは、注釈の消費者です。 @Overrideのような注釈の場合は、Javaコンパイラ自体、または静的コード解析ツール、またはIDEにあります。

+1

オーバーライドアノテーションのソースコードを知っています。しかし、それは内部的にどのように働いているのですか?どのようにこのメソッドがオーバーライドメソッドであるか、またはこれがオーバーライドメソッドであるかどうかを確認することができますか?カスタムオーバーライドアノテーションを作成できますか?それはJavaのオーバーライドアノテーション –

+2

のように正確に同じ動作をする必要があります私は私の答えで言ったように、**動作は注釈の一部ではありません。**解釈は、注釈を消費するものにあります。そのため、コンシューマを変更しない限り、 '@ Override'(または他の標準アノテーション)のカスタムバージョンを実際に作成することはできません。 –

3

これに続いてlinkです。これは、あなたの問題に近い答えを提供します。 Javaのアノテーションに注目した場合、アノテーションはJava 5で導入され、Spring固有のものではありません。一般に、アノテーションを使用すると、クラス、メソッド、または変数にメタデータを追加できます。アノテーションは、コンパイラ(@Overrideアノテーションなど)またはSpringなどのフレームワーク(@Componentアノテーションなど)によって解釈できます。

さらに、参考資料を追加しています。

  1. http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample
+0

@ LuigiMendoza java 1.7 annotation docが追加されました –

+0

@Ruchira私はすべてのリンクを開いていましたが、まだそれはどのように処理されていません。春の注釈のように細かく説明できますか?私は、spring.xmlファイルに設定を書き込まずにアノテーションを使ってすべてのことを行うことができます。注釈を内部的にXML設定にバインドしていますか? –

+0

@ChiragDasaniこれを見てみましょう。これはhttp://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s11.html に役立つことがあります。また、この記事を参照してください。http://stackoverflow.com/questions/2798181/実際の作業のためのフレームワークのようなものです。 –

2

基本的に、注釈は、コンパイラまたはアプリケーションによって読み取られるだけマーカーです。 保持ポリシーによっては、コンパイル時にのみ使用できます。または、リフレクションを使用して実行時に読み取り可能です。

多くのフレームワークは実行時の保持を使用します。すなわち、クラス、メソッド、フィールドなどにいくつかの注釈があるかどうかを反射的にチェックし、注釈が存在するかどうかを確認します。さらに、アノテーションのメンバを使用して詳細情報を渡すこともできます。

19

他にも示唆されていること以外に、カスタマイズされた注釈とそのプロセッサを最初から書き、注釈の仕組みを確認することをおすすめします。

たとえば、コンパイル時にメソッドが多重定義されているかどうかを確認するためのアノテーションを作成しました。

まず、Overloadという名前の注釈を作成します。この注釈は、定義されたアノテーションによって注釈要素を処理するために、対応するプロセッサを作成するので、私は@Target(value=ElementType.METHOD)

package gearon.customAnnotation; 

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

@Target(value=ElementType.METHOD) 
public @interface Overload { 

} 

と次にそれに注釈を付ける方法に適用されます。 @Overloadによって注釈が付けられたメソッドの場合、その署名は複数回出現する必要があります。または、エラーが出力されます。

package gearon.customAnnotation; 

import java.util.HashMap; 
import java.util.Map.Entry; 
import java.util.Set; 

import javax.annotation.processing.AbstractProcessor; 
import javax.annotation.processing.RoundEnvironment; 
import javax.annotation.processing.SupportedAnnotationTypes; 
import javax.lang.model.element.Element; 
import javax.lang.model.element.TypeElement; 
import javax.tools.Diagnostic.Kind; 

@SupportedAnnotationTypes("gearon.customAnnotation.Overload") 

public class OverloadProcessor extends AbstractProcessor{ 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
     // TODO Auto-generated method stub 
     HashMap<String, Integer> map = new HashMap<String, Integer>(); 

     for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){ 
      String signature = element.getSimpleName().toString(); 
      int count = map.containsKey(signature) ? map.get(signature) : 0; 
      map.put(signature, ++count); 
     } 

     for(Entry<String, Integer> entry: map.entrySet()){ 
      if(entry.getValue() == 1){ 
       processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() + " has not been overloaded"); 
      } 
     } 
     return true; 
    } 
} 

jarファイルに注釈し、そのプロセスをパッケージ化した後、@Overloadを持つクラスを作成し、それをコンパイルするのjavac.exeを使用しています。

import gearon.customAnnotation.Overload; 

public class OverloadTest { 
    @Overload 
    public static void foo(){ 
    } 

    @Overload 
    public static void foo(String s){ 

    } 

    @Overload 
    public static void nonOverloadedMethod(){ 

    } 
} 

nonOverloadedMethod()が実際にオーバーロードされていなかったので、私たちは以下のような出力が得られます:

enter image description here

+0

上記の情報はJDK6に関しては非常に良いですが(+1)、JDK5を使って同じことを達成する方法は?JDK6 SupportedAnnotationTypes、AbstractProcessorクラスを使用すると、以前より簡単になったのですが(Spring FrameWork 2.5 for jdk5など)、JVMがjdk5のクラスのような注釈プロセッサを検出する方法は? 2つのセクション(1つはJDK5、もう1つはJdk6 +の現在のバージョン)で答えを編集してガイドをお願いしますか? – RawAliasCoder

+0

非常に良い例 –

関連する問題