web-dev-qa-db-de.com

Java Generics - Warum ist "Erweitert T" erlaubt, aber nicht "Implementiert T"?

Ich frage mich, ob es in Java einen besonderen Grund gibt, immer "extends" anstelle von "implements" zum Definieren von Schranken von Typparametern zu verwenden.

Beispiel: 

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

ist aber verboten 

public class A<B extends C>{} 

ist richtig. Was ist der Grund dafür?

272
user120623

In der generischen Einschränkungssprache gibt es keinen semantischen Unterschied, ob eine Klasse "implementiert" oder "erweitert". Die Einschränkungsmöglichkeiten sind 'extend' und 'super' - das heißt, diese Klasse soll mit dieser anderen Klasse arbeiten (erweitert werden) oder diese Klasse kann von dieser Klasse (super) zugewiesen werden.

316
Tetsujin no Oni

Die Antwort ist in hier

Um einen gebundenen Typparameter zu deklarieren, listen Sie den Namen des Typparameters auf, gefolgt von dem Schlüsselwort extends, gefolgt von der Obergrenze der Obergrenze […]. Beachten Sie, dass in diesem Zusammenhang Erweiterungen im Allgemeinen verwendet werden, um entweder extends (wie in Klassen) oder implements (wie in Schnittstellen) zu bedeuten.

Da haben Sie es, es ist etwas verwirrend, und Oracle weiß es.

53
MikaelF

Wahrscheinlich, weil für beide Seiten (B und C) nur der Typ relevant ist, nicht die Implementierung. In Ihrem Beispiel

public class A<B extends C>{}

B kann auch eine Schnittstelle sein. "Erweitert" wird verwendet, um Subschnittstellen sowie Unterklassen zu definieren.

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

Normalerweise denke ich an "Sub Erweitert Super" als " Sub ist wie Super , aber mit zusätzlichen Fähigkeiten" und "Clz implementiert Intf" als " Clz ist eine Realisierung von Intf '. In Ihrem Beispiel würde dies passen:Bist wieC, jedoch mit zusätzlichen Funktionen. Die Fähigkeiten sind hier relevant, nicht die Realisierung.

16
beetstra

Es kann sein, dass der Basistyp ein generischer Parameter ist, der tatsächliche Typ kann also eine Schnittstelle einer Klasse sein. Erwägen:

class MyGen<T, U extends T> {

Auch aus Client-Code-Sicht sind Schnittstellen von Klassen kaum zu unterscheiden, wohingegen es für den Untertyp wichtig ist.

Hier ist ein ausführlicheres Beispiel, wo Erweiterungen erlaubt sind und möglicherweise was Sie möchten:

public class A<T1 extends Comparable<T1>>

7
ntg

Es ist irgendwie willkürlich, welche der Begriffe zu verwenden sind. Es könnte so oder so gewesen sein. Möglicherweise dachten die Sprachdesigner, dass der Begriff "erweitert" als der grundlegendste Begriff und "implementiert" als Spezialfall für Schnittstellen gilt.

Aber ich denke, implements wäre etwas sinnvoller. Ich denke, das kommuniziert mehr darüber, dass die Parametertypen nicht in einer Vererbungsbeziehung sein müssen, sie können sich in any einer Art von Subtyp-Beziehung befinden.

Das Java-Glossar drückt ein ähnliche Ansicht aus.

5
Lii

Das "Erweitert" bedeutet in diesem Zusammenhang ebenso wie Implementierungen in Schnittstellen und Erweiterungen in Klassen. Hier ist mehr Erklärung

1
The_Martian

Wir sind gewohnt an

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

und jede leichte Abweichung von diesen Regeln verwirrt uns sehr.

Die Syntax einer Typbindung ist definiert als

TypeBound:
    extends TypeVariable 
    extends ClassOrInterfaceType {AdditionalBound}

( JLS 12> 4.4. Typvariablen> TypeBound )

Wenn wir es ändern würden, würden wir sicherlich den Fall implements hinzufügen

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

und am Ende mit zwei identisch verarbeiteten Klauseln

ClassOrInterfaceType:
    ClassType 
    InterfaceType

( JLS 12> 4.3. Referenztypen und -werte> ClassOrInterfaceType )

außer wir müssten uns auch um implements kümmern, was die Sache noch komplizierter machen würde.

Ich glaube, es ist der Hauptgrund, warum extends ClassOrInterfaceType anstelle von extends ClassType und implements InterfaceType verwendet wird - um die Dinge innerhalb des komplizierten Konzepts einfach zu halten. Das Problem ist, dass wir nicht das richtige Wort haben, um sowohl extends als auch implements zu behandeln, und wir wollen definitiv kein Wort einführen.

<T is ClassTypeA>
<T is InterfaceTypeA>

extends bringt zwar einiges an Chaos mit sich, ist aber ein weiter gefasster Begriff und kann zur Beschreibung beider Fälle verwendet werden. Versuchen Sie, Ihren Verstand auf das Konzept von Erweiterung eines Typs (nicht eine Klasse erweiternnicht implementierung einer Schnittstelle). Sie schränken einen Typparameter durch einen anderen Typ ein, und es spielt keine Rolle, um welchen Typ es sich handelt. Es ist nur wichtig, dass es sich um die Obergrenze und den Supertyp handelt.

1
Andrew Tobilko