2016-09-29 15 views
1

私はjavaで奇妙なジェネリックを試しています。次のコードでは、fooのオーバーライドは機能しますが、barのオーバーライドは機能しません。なぜか分からない。奇妙なジェネリックのJavaメソッドのオーバーライドエラー

2つのオーバーライドの唯一の違いは、MBの制約にあることに注意してください。 fooを無効にすると、MBAlpha<B, MB>に拡張され、機能します。 barMBをオーバーライドすると、Beta<B, MB>Alpha<B, MB>に拡張されても、Beta<B, MB>が拡張され、機能しません。

MB extends Beta<B, MB>Beta<A, MA> extends Alpha<A, MA>は、MB extends Alpha<B, MB>を意味すると思います。ではなぜそれは機能しませんか?

import java.util.function.Function; 

abstract class Alpha<A, MA extends Alpha<A, MA>> { 
    abstract public <B, MB extends Alpha<B, MB>> MB foo(Function<A, B> f); 
    abstract public <B, MB extends Alpha<B, MB>> MB bar(Function<A, B> f); 
} 

class Beta<A, MA extends Beta<A, MA>> extends Alpha<A, MA> { 
    @Override public <B, MB extends Alpha<B, MB>> MB foo(Function<A, B> f) { return null; } 
    @Override public <B, MB extends Beta<B, MB>> MB bar(Function<A, B> f) { return null; } 
} 
+1

同じ問題の[ここに簡略化されたバージョン](http://ideone.com/j9QkOG)。ジェネリックメソッドをオーバーライドするときは、型パラメーターの境界を変更することはできません。 – Radiodef

+1

関連するhttp://stackoverflow.com/questions/23438813/cannot-override-generic-interface – Tunaki

+0

OKの人、私は今理解しています。要約すると、ジェネリック型の境界を変更しながらメソッドをオーバーライドすることはできません。期間。これは、ジェネリック型とイベントの使用方法に関係なく、使用するかどうかに関係なく使用されます。 –

答えて

2

差が制約MB extends Beta<B, MB>MB extends Alpha<B, MB>と同じではないということです。したがって、barメソッドをオーバーライドしていません。

the error message saysのように:だから

Main.java:10: error: name clash: <B#1,MB#1>bar(Function<A#1,B#1>) in Beta and <B#2,MB#2>bar(Function<A#2,B#2>) in Alpha have the same erasure, yet neither overrides the other 
    @Override public <B, MB extends Beta<B, MB>> MB bar(Function<A, B> f) { return null; } 

、あなたはBeta.barが本当にAlpha.barを上書きしないように、あなたの一般的な制約を変更する必要があります。

+0

ありがとうございます。私はそれが同じ制約ではないことを理解しています。しかし、バーのMBの制約はより具体的です。戻り型として使用されます。したがって、Beta.barはAlpha.barと互換性のない値を返すことはできません。だからそれは大丈夫だろう。 –

+0

OK、私はあなたの答えをその質問に答えるのに最も近いものとして受け入れました。たぶん、ジェネリックタイプがどのように使用されているかどうかは関係ありません。 –

1

私は、MBはベータ版< Bを拡張することを期待し、MB >とベータ< A、MA >はアルファ< A、MA >はMBがアルファ< B、MB >を拡張暗示する拡張。 Beta<A, MB>を拡張することすべてがMBAlpha<A, MB>を拡張

上記の文は正しいですが

は、それは問題ではありません。 2つのメソッドのシグネチャ

abstract public <B, MB extends Alpha<B, MB>> MB bar(Function<A, B> f); 

public <B, MB extends Beta<B, MB>> MB bar(Function<A, B> f); 

は、実際に異なっています!これらのメソッドは異なる引数を受け入れます。私がclass Gamma<A, MA extends Gamma<B, Gamma>> extends Alpha<A, MA>を持っていたとします。抽象クラスAlphaの指定により、のオブジェクトはAlphaのサブクラスであるため、barはオブジェクトGammaを返すことができます。しかし、の "オーバーライド"バージョンではBetaのタイプはGammaBetaのサブクラスではないため、タイプGammaを返すことができませんでした。したがって、これらの2つのメソッドシグネチャは、実際には異なる動作をし、無効な無効化を無効にします。

+0

しかし、Beta.barはAlpha.barにできるものを返す義務を負いません。オーバーライドを無効にするべきではありません。より具体的な型を返す新しい実装でメソッドをオーバーライドできます。 –

+0

私はあなたの意見を見ます。私の推測では、型引数による返り引数にのみ影響を与えるジェネリック引数にかかわらず、Javaではオーバーライド中にジェネリックを絞り込むことができないため、他の型に影響を与える可能性があります。関数)。 –

+1

あなたは正しい考えを持っていますが、ここで問題となるのは戻り値の型ではありません。共変の戻り値の型はJavaでは問題ありません([here here](http://stackoverflow.com/a/1882587/2891664)参照))。問題は、型パラメータの宣言です。 – Radiodef

関連する問題