web-dev-qa-db-ja.com

なぜJavaクラスは実装されたインターフェースから注釈を継承しないのですか?

GuiceのAOPを使用して、いくつかのメソッド呼び出しをインターセプトしました。私のクラスはインターフェイスを実装しています。Guiceが適切なメソッドを選択できるように、インターフェイスメソッドに注釈を付けたいと思います。アノテーションのタイプに Inherited アノテーションが付けられている場合でも、クラスを実装するアノテーションはInheritedのJava doc:

また、このメタ注釈は、注釈がスーパークラスからのみ継承されることに注意してください。実装されたインターフェースの注釈は効果がありません。

この理由は何でしょうか?オブジェクトのクラスが実行時に実装するすべてのインターフェイスを知ることはそれほど難しいことではないので、この決定の背後には正当な理由がなければなりません。

103
Boris Pavlović

その理由は、そうしないと多重継承の問題が発生するからだと思います。

例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

これを行う場合:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

結果はどうなりますか? 「baz」、「phleem」、または「flopp」?


このため、インターフェース上の注釈はほとんど役に立ちません。

125

@ -Inheritedの Javadoc から:

注釈タイプが自動的に継承されることを示します。継承されたメタ注釈が注釈型宣言に存在し、ユーザーがクラス宣言で注釈型を照会し、クラス宣言にこの型の注釈がない場合、クラスのスーパークラスは注釈型に対して自動的にクエリされます。このプロセスは、このタイプの注釈が見つかるか、クラス階層の最上位(オブジェクト)に達するまで繰り返されます。このタイプの注釈を持つスーパークラスがない場合、クエリは、問題のクラスにそのような注釈がないことを示します。注釈付きのタイプを使用してクラス以外の注釈を付ける場合、このメタ注釈タイプは効果がないことに注意してください。また、このメタ注釈は、注釈がスーパークラスからのみ継承されることに注意してください。実装されたインターフェースの注釈は効果がありません。

一方、JSR 305バリデーターは、ある種の継承ルックアップを行います。クラスの階層がある場合:

_//Person.Java
@Nonnull
 public Integer getAge() {...}

//Student.Java (inherits from Person)
@Min(5)
public Integer getAge() {...}
_

Student.getAge()の有効な検証は@Nonnull @Min(5)です。 _@Nonnull_には_@Inherited_メタ注釈がありません。

33
Eric Jablow