ジェネリックメソッドの「違法な」実装:コンパイルエラーが発生しないのはなぜですか?


8

私はこのシグネチャを持つメソッドを含むインターフェースを持っています:

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

基本的には、MergePropertyないクラスではありません実装RestartApplicant、そしてRestartApplicant本当にこの問題を理解するために重要ではありません方法を含む機能のインタフェースです。

これが問題です。このインターフェイスを実装するクラスを作成すると、Javaを使用すると、次のコードをコンパイルエラーなしで実行できます。

public class MyImplementation implements MyInterfacePreviouslyDescribed {

    @Override
    public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }
}

明らかに、私はそこでの実装の制限を尊重していません。このシグネチャが与えられた場合、使用Arrays.asList(...)して返すリストには、を実装する要素を含める必要はありませRestartApplicantMergeProperty実装しないでくださいRestartApplicant。したがって、これはおそらくどこかにキャストエラーを引き起こすことになります。

それでも、警告が表示されます:

Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>

私の質問は、なぜ警告しか出ないのですか?コードをコンパイルできないように思えます。何か特別な理由はありますか?

前もって感謝します。

編集

コードを少し遊んだ後、「ジェネリック宣言」をクラスレベルに移動すると、次のようになるとわかりました。

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>

ただの代わりに

interface MyInterfacePreviouslyDescribed<T>

そして明らかに

List<P> loadPropertiesFrom(T p1, T p2);

の代わりに

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

次に、以前と同じ「不正な」実装を試行すると、実際コンパイルエラーが発生します。それはさらに奇妙に見えます...

回答:


2

あなたも行うことができます:

    @Override
    public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }

最初のケースでは。これは、オーバーライドされたメソッドがジェネリックではなく、これらの消去が行われるためListです。なぜこれが許可されるのですか?正直なところ、わかりません。下位互換性に関係している可能性があります。

あなたの2番目の例では、それは本当にそうでなければならないようです:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {

実装では、型を強制的に正しいものにします。実際、2番目の例は直感的なものです。コンパイルされないためです。そしてそれ期待されています。一方、最初のものは、同じ消去にオーバーライドできる非ジェネリックメソッドの互換性ルールに依存しています。


面白い。結局のところ、2番目の例は確かにより直感的です。そして、そうです、後者に欠けていた「T」はタイプミスでした
Akami
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.