Ich frage mich, ob es in Java einen besonderen Grund gibt, immer " extends
" statt " implements
" für die Definition von Grenzen 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?
java
generics
syntax
design-choices
user120623
quelle
quelle
implements
?" - "Weil es nur gibtextends
".implements
nichts Neues bringen und die Dinge weiter komplizieren würde. Ich hoffe es wird hilfreich für Sie sein.Antworten:
Es gibt keinen semantischen Unterschied in der generischen Einschränkungssprache zwischen der Implementierung oder Erweiterung einer Klasse. Die Einschränkungsmöglichkeiten sind 'erweitert' und 'super' - das heißt, diese Klasse kann mit der anderen zuweisbar (erweitert) arbeiten, oder ist diese Klasse von dieser zuweisbar (super).
quelle
class Generic<RenderableT extends Renderable implements Draggable, Droppable, ...> { Generic(RenderableT toDrag) { x = (Draggable)toDrag; } }
man Zeitprüfungen kompiliert.Die Antwort ist hier :
Da haben Sie es also, es ist ein bisschen verwirrend und Oracle weiß es.
quelle
getFoo(List<? super Foo> fooList)
vergrößern, funktioniert NUR mit der Klasse, die buchstäblich von Foo wie erweitert wirdclass Foo extends WildcardClass
. In diesem FallList<WildcardClass>
wäre eine Eingabe akzeptabel. Eine Klasse,Foo
die nicht funktioniert,class Foo implements NonWorkingWildcardClass
bedeutet jedoch nicht,List<NonWorkingWildcardClass>
dass sie in der gültig istgetFoo(List<? super Foo> fooList)
. Kristallklar!Wahrscheinlich, weil für beide Seiten (B und C) nur der Typ relevant ist, nicht die Implementierung. In deinem Beispiel
B kann auch eine Schnittstelle sein. "erweitert" wird verwendet, um Unterschnittstellen sowie Unterklassen zu definieren.
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 übereinstimmen: B ist wie C , jedoch mit zusätzlichen Funktionen. Die Fähigkeiten sind hier relevant, nicht die Realisierung.
quelle
Es kann sein, dass der Basistyp ein generischer Parameter ist, sodass der tatsächliche Typ eine Schnittstelle einer Klasse sein kann. Erwägen:
Auch aus Sicht des Client-Codes sind Schnittstellen kaum von Klassen zu unterscheiden, während dies für den Subtyp wichtig ist.
quelle
Hier ist ein ausführlicheres Beispiel dafür, wo Erweiterungen zulässig sind und möglicherweise was Sie möchten:
public class A<T1 extends Comparable<T1>>
quelle
Es ist irgendwie willkürlich, welche der Begriffe verwendet werden sollen. Es hätte so oder so sein können. Vielleicht dachten die Sprachdesigner, dass "erweitert" der grundlegendste Begriff ist und "implementiert" als Sonderfall für Schnittstellen.
Aber ich denke, das
implements
wäre etwas sinnvoller. Ich denke, das kommuniziert mehr, dass die Parametertypen nicht in einer Vererbungsbeziehung sein müssen, sie können in jeder Art von Subtypbeziehung sein.Das Java-Glossar vertritt eine ähnliche Ansicht .
quelle
Wir sind gewohnt an
und jede geringfügige Abweichung von diesen Regeln verwirrt uns sehr.
Die Syntax eines gebundenen Typs ist definiert als
( JLS 12> 4.4. Typvariablen>
TypeBound
)Wenn wir es ändern würden, würden wir den
implements
Fall sicherlich hinzufügenund am Ende zwei identisch verarbeitete Klauseln
( JLS 12> 4.3. Referenztypen und Werte>
ClassOrInterfaceType
)außer wir müssten uns auch darum kümmern
implements
, was die Sache noch komplizierter machen würde.Ich glaube, es ist der Hauptgrund, warum
extends ClassOrInterfaceType
anstelle vonextends ClassType
undimplements InterfaceType
- verwendet wird, um die Dinge innerhalb des komplizierten Konzepts einfach zu halten. Das Problem ist , dass wir nicht das richtige Wort sowohl zur Deckung habenextends
undimplements
wir definitiv nicht wollen , eine einzuführen.<T is ClassTypeA>
<T is InterfaceTypeA>
Obwohl
extends
es mit einer Schnittstelle etwas Chaos bringt, ist es ein weiter gefasster Begriff und kann verwendet werden, um beide Fälle zu beschreiben. Versuchen Sie, sich auf das Konzept der Erweiterung eines Typs einzustellen (keineKlasse erweitern, keineSchnittstelle implementieren). Sie beschränken einen Typparameter auf einen anderen Typ, und es spielt keine Rolle, um welchen Typ es sich tatsächlich handelt. Es ist nur wichtig, dass es seine Obergrenze und sein Supertyp ist .quelle
Bei Verwendung von generic on interface wird das Schlüsselwort sogar erweitert . Hier ist das Codebeispiel:
Es gibt zwei Klassen, die die Begrüßungsschnittstelle implementieren:
Und der Testcode:
quelle