1

Java アノテーションを理解するために、私は実際に試してみましたが、実行を見るとまだ混乱していますが、疑問はほとんどありませんでした。これが私がやっていることです。注釈を定義する

@Retention(RetentionPolicy.CLASS)
@Target(value=ElementType.TYPE)
public @interface Command {

}

今、私はコマンドを初期化します

       Reflections reflections = new Reflections(CMDS_PACKAGE);
       Set<Class<?>> allClasses = reflections.getTypesAnnotatedWith(Command.class); // line 2

        for (Class clazz : allClasses) {
            MYCommand cmd = (MYCommand) clazz.newInstance();
            System.out.println(cmd.getClass().getAnnotation(Command.class));// line 6
            log.info("loading Command [ {} ]", clazz.getCanonicalName());
        }

プログラムを実行すると、6行目が表示されますnull。ポリシーが RetentionPolicy.RUNTIME6 行目の場合、正しいコマンドが表示されます。

このプロセスの間、2 行目は、ポリシーに関係なく、正しい Annotated クラスを提供しています。つまり、リフレクションライブラリが無視していることを意味しますか?RetentionPolicy

ほとんどのチュートリアルを読んでも、本当に混乱しています。

私にとって実際の問題は、なぜこの異なる動作なのかということです。ポリシーで注釈を付けた場合RetentionPolicy.CLASS 、実行時に私に与えられるべきではありませんでした。私の理解は間違っていますか、誰かがこれらの両方の理解に関する貴重な情報を共有してください。

4

2 に答える 2

0

まず第一にRetentionPolicy、準拠するコンパイラが何をしなければならないかを指示します。AnnotationsRetentionPolicy.SOURCEはクラス ファイルに含まれませんが、他の 2 つRetentionPolicy.CLASSRetentionPolicy.RUNTIMEはクラス ファイル内に格納されますが、異なる属性を使用して、クラス ファイルを読み取るときにそれらを区別できるようにします。

ドキュメントにRetentionPolicy.CLASSは次のように書かれています:

注釈は、コンパイラによってクラス ファイルに記録されますが、実行時に VM によって保持される必要はありません。これがデフォルトの動作です。

ここでは、責任が明確に文書化されており、VMは責任を保持せず、JRE に組み込まれている Reflection API はそれに準拠しています。「保持する必要がない」というのは、強い要件のようには聞こえませんが。

ただし、使用しているReflection Libraryなどのサードパーティのライブラリは、クラスファイルを解析するときに必要なものを自由に実装できます. 呼び出したメソッドのドキュメントには、「特定の注釈で注釈が付けられた型を取得する」と単純に記載されているため、型にその注釈があるため、動作は間違っていません。

また、 のを分析することで、そのメソッドを呼び出す前であっRetentionPolicyても、 のを見つけることができます。したがって、メソッドが何もしないのではなく何かを行うため、アノテーションに が含まれていることがわかっているときにメソッドを呼び出しても意味がありません。AnnotationAnnotationsAnnotationRetentionPolicy.CLASS

しかし、もちろん、その動作が完全に文書化された方がよいでしょう。そのため、そのサードパーティ ライブラリの作成者にドキュメントの改善を依頼することができます。

于 2014-01-17T09:54:15.173 に答える
0

はい、Reflection ライブラリ(Reflection ではなく Reflection* s *) は、デフォルトで注釈の可視性を無視します。これは、 org.reflections.adapters.JavassistAdapter#includeInvisibleTagフラグを使用して変更できます 。何かのようなもの:

JavassistAdapter mdAdapter = new JavassistAdapter();
mdAdapter.includeInvisibleTag = false;

new Reflections(new ConfigurationBuilder()
    ...
    .setMetadataAdapter(mdAdapter)
    ...

もう 1 つのオプションは、代わりに JavaReflectionAdapter を使用することです。

HTH

于 2014-01-20T09:49:56.410 に答える