web-dev-qa-db-ja.com

Javaジェネリック-「Tの拡張」は許可されているが、「Tの実装」は許可されていないのはなぜですか。

型パラメーターの境界を定義するために「extends」ではなく、常に「implements」を使用する特別な理由がJavaにあるのだろうか。

例:

public interface C {}
public class A<B implements C>{} 

禁止されていますが

public class A<B extends C>{} 

正しい。その理由は何ですか?

279
user120623

ジェネリック制約言語には、クラスが「実装する」か「拡張する」かの間で意味的な違いはありません。制約の可能性は、「extends」と「super」です。つまり、このクラスは他のクラスに割り当て可能に動作する(extends)か、このクラスはそのクラスから割り当て可能(super)です。

320
Tetsujin no Oni

答えは here にあります:

制限された型パラメーターを宣言するには、型パラメーターの名前、extendsキーワード、そのupper bound[…]の順にリストします。このコンテキストでは、extends(クラスの場合)またはimplements(インターフェイスの場合)のいずれかを意味する一般的な意味で、extendsが使用されることに注意してください。

そこにあなたはそれを持っています、それは少し混乱します、そしてオラクルはそれを知っています。

56
MikaelF

おそらく、両側(BとC)には、実装ではなく型のみが関係しているためです。あなたの例では

public class A<B extends C>{}

Bもインターフェイスにすることができます。 「拡張」は、サブインターフェースとサブクラスを定義するために使用されます。

interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}

私は通常、「Sub extends Super」を「SubSuperに似ていますが、追加機能がある」と考え、「ClzはIntfを実装します」を「ClzIntf 'の実現です。あなたの例では、これは一致します:BCに似ていますが、追加機能があります。ここでは、機能は実現ではなく関連しています。

17
beetstra

基本型は汎用パラメーターである可能性があるため、実際の型はクラスのインターフェイスである可能性があります。考慮してください:

class MyGen<T, U extends T> {

また、クライアントコードの観点からは、インターフェイスはクラスとほとんど区別できませんが、サブタイプの場合は重要です。

次に、拡張が許可される場所と、おそらく必要なもののより複雑な例を示します。

public class A<T1 extends Comparable<T1>>

7
ntg

どの用語を使用するかは任意です。どちらの方法でもかまいません。おそらく、言語設計者は、「拡張」を最も基本的な用語として、「実装」をインターフェイスの特殊なケースと考えていたのでしょう。

しかし、implementsはもう少し意味があると思います。パラメータタイプが継承関係にある必要はなく、anyのサブタイプ関係にあることをより伝えていると思います。

Java用語集は、 類似したビュー を表します。

5
Lii

このコンテキストでの「拡張」とは、インターフェイスで実装し、クラスで拡張するようなものです。 詳細はこちら

1
The_Martian

私たちは慣れています

class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}

そして、これらの規則からのわずかな逸脱は、私たちを大きく混乱させます。

型バインドの構文は次のように定義されます

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

JLS 12> 4.4。型変数> TypeBound

変更する場合は、必ずimplementsケースを追加します

TypeBound:
    extends TypeVariable 
    extends ClassType {AdditionalBound}
    implements InterfaceType {AdditionalBound}

そして、同様に処理された2つの句になります

ClassOrInterfaceType:
    ClassType 
    InterfaceType

JLS 12> 4.3。参照タイプと値> ClassOrInterfaceType

ただし、implementsも処理する必要がありますが、これは事態をさらに複雑にします。

私は、extends ClassOrInterfaceTypeextends ClassTypeの代わりにimplements InterfaceTypeが使用される主な理由だと思います-複雑な概念の中で物事をシンプルに保つためです。問題は、extendsimplementsの両方をカバーする適切なWordを持っていないことであり、絶対に紹介したくありません。

<T is ClassTypeA>
<T is InterfaceTypeA>

extendsは、インターフェースと一緒に使用すると混乱を招きますが、より広義の用語であり、両方のケースを説明するために使用できます。 タイプを拡張するという概念に心を合わせてみてください クラスを拡張する、ではない インターフェースの実装)。型パラメーターを別の型で制限し、その型が実際に何であるかは関係ありません。重要なのは、その上限とそのスーパータイプです。

1
Andrew Tobilko