@Overrideのような注釈は、Javaの内部でどのように機能しますか?


90

誰かがJavaの内部で注釈がどのように機能するかを私に説明できますか?

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

どなたか詳しくご説明いただければ幸いです。


4
「社内で働く」とはどういう意味ですか?コンパイラー?ランタイム?
chrylis -cautiouslyoptimistic- 2013

3
@chrylis Workは、内部的には、このメソッドがオーバーライドメソッドであるか、またはこのメソッドがオーバーライドメソッドではないことを自動的に識別する方法を意味します。それは両方の時間に働きます。コンパイル時のオーバーライドアノテーションの動作や、実行時のスプリングコントローラーアノテーションの動作など
Chirag Dasani 2013

回答:


137

アノテーションの種類の最初の主な違いは、それらがコンパイル時に使用されてから破棄される(のように@Override)か、コンパイル済みクラスファイルに配置されて実行時に使用できる(Springのように@Component)かです。これは、アノテーションの@Retentionポリシーによって決定されます。独自のアノテーションを作成する場合、そのアノテーションが実行時に役立つか(おそらく自動構成の場合)、コンパイル時にのみ役立つか(チェックまたはコード生成の場合)を決定する必要があります。

注釈付きのコードをコンパイルする場合、コンパイラーは、アクセス修飾子(public/ private)やのようなソース要素の他の修飾子と同じように注釈を表示しますfinal。アノテーションに遭遇すると、特定のアノテーションに興味があると言うプラグインクラスのようなアノテーションプロセッサを実行します。注釈プロセッサは通常、リフレクションAPIを使用してコンパイルされる要素を検査し、それらの要素に対してチェックを実行したり、要素を変更したり、コンパイルする新しいコードを生成したりできます。@Override最初の例です。リフレクションAPIを使用して、スーパークラスの1つでメソッドシグネチャの一致を検出できることを確認し、一致しMessagerない場合はを使用してコンパイルエラーを発生させます。

注釈プロセッサの作成に関するチュートリアルは多数あります。ここに便利なものがあります。インターフェースのメソッドを調べて、コンパイラーが注釈プロセッサーを呼び出す方法を確認Processorます。主な操作はprocessメソッドで行われます。このメソッドは、一致する注釈を持つ要素をコンパイラが検出するたびに呼び出されます。


3
Springのアノテーションプロセッサが@Componentを解析し、クラスをそのコンテナに挿入する方法を正確に示すとよいでしょう
Junchen Liu

@shanyangquこれは、Spring固有ではない質問のトピックから外れています。ポストプロセッサクラスは自分で読むことができます。
クリリス

41

他の人が提案したことに加えて、カスタマイズされた注釈とそのプロセッサをゼロから記述して、注釈の動作を確認することをお勧めします。

たとえば、私自身では、コンパイル時にメソッドがオーバーロードされているかどうかを確認するための注釈を記述しました。

まず、という名前の注釈を作成します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ファイルにパッケージ化した後、@Overloadjavac.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()、実際にオーバーロードされていない、私たちは以下のような出力が得られます。

ここに画像の説明を入力してください


上記の情報はJDK6(+1)に関して非常に敬意を表していますが、JDK5を使用して同じことを実現するにはどうすればよいですか?JDK6のSupportedAnnotationTypes、AbstractProcessorクラスを使用すると簡単になりましたが、過去に同じことが起こった(jdk5上のSpring FrameWork 2.5など)?JVMがjdk5のクラスのような注釈プロセッサを検出する方法?2セクションの回答を編集してガイドしてください(JDK5用、現在のバージョンはJdk6 +用)?
プラジットガンジー2017年

あなたのクラスではOverloadProcessor::processなぜentry.getValue() == 1ですか?親クラス/インターフェースに注釈を追加する必要roundEnv.getElementsAnnotatedWith(Overload.class)がないので、親クラス/インターフェースを取得しませんか?

私はこの部分で混乱していますが、あなたの答えは非常に役に立ちます。

@s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼メソッドがオーバーロードとして扱われる場合、少なくとも同じ名前の別のメソッドがクラスで定義されている必要があります。
ユージーン

1
@RainingメソッドがOverloadedと言う場合は、同じクラスに複数回出現する必要がありますが、 `== 1`の場合はエラーになります。
KrishPrabakar

5

ここにあります@Overridehttp : //www.docjar.com/html/api/java/lang/Override.java.html

自分で書くかもしれない注釈と区別する特別なことは何もありません。興味深い部分は、注釈の消費者にあります。のようなアノテーションの場合@Override、それはJavaコンパイラ自体、静的コード分析ツール、またはIDEにあります。


1
私はそのオーバーライドコードのソースコードを知っています。しかし、それが内部でどのように機能するか。どのようにしてこのメ​​ソッドがオーバーライドメソッドではないのか、またはこれがオーバーライドメソッドであるのかを特定できますか?または、カスタムオーバーライドアノテーションを作成できますか?Javaオーバーライドアノテーションとまったく同じように動作するはずです
Chirag Dasani 2013

3
回答で述べたように、動作は注釈の一部ではありません。解釈は注釈を消費するものにあります。そのため、コンシューマを変更しない限り、独自のカスタムバージョン@Override(または他の標準アノテーション)を実際に作成することはできません。
マットボール

3

基本的に、注釈はコンパイラまたはアプリケーションによって読み取られる単なるマーカーです。それらの保持ポリシーに応じて、コンパイル時にのみ使用できるか、実行時にリフレクションを使用して読み取ることができます。

多くのフレームワークはランタイム保持を使用します。つまり、クラス、メソッド、フィールドなどにいくつかの注釈が存在するかどうかを反射的にチェックし、注釈が存在する(または存在しない)場合に何かを行います。さらに、注釈のメンバーを使用して、さらに情報を渡すことができます。


3

このリンクに従ってください。これはあなたの問題に近い答えを提供します。でアノテーションに焦点を当てた場合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

@LuiggiMendoza java 1.7アノテーションドキュメントが追加されました
Ruchira Gayan Ranaweera 2013

@Ruchira私はすべてのリンクを開いたが、それでもそれがどのように機能するのか明確になっていない。春の注釈として検討するなど、詳細を説明できますか?spring.xmlファイルに構成を記述せずに、アノテーションを使用してすべてのことを実行できます。内部的にアノテーションをXML構成にバインドしていますか?
Chirag Dasani 2013

@ChiragDasaniはこれを見てください。これは、あなたに役立つかもしれstatic.springsource.org/spring/docs/3.0.0.M3/reference/html/...をしても、このSO記事参照stackoverflow.com/questions/2798181/...
Ruchira Gayan Ranaweera

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.