Wer erweitert Schnittstellen? Und warum?

20

AFAIK, meine Klasse extendsElternklassen und implementsSchnittstellen. Aber ich stoße auf eine Situation, die ich nicht nutzen kann implements SomeInterface. Es ist die Deklaration eines generischen Typs. Beispielsweise:

public interface CallsForGrow {...}

public class GrowingArrayList <T implements CallsForGrow>  // BAD, won't work!
                              extends ArrayList<T> 

Hier ist das Verwenden implementssyntaktisch verboten. Ich dachte zuerst, dass die Verwendung der Schnittstelle in <> überhaupt verboten ist, aber nein. Es ist möglich, dass ich nur extendsanstelle von verwenden muss implements. Infolgedessen "erweitere" ich eine Schnittstelle. Dieses andere Beispiel funktioniert:

public interface CallsForGrow {...}

public class GrowingArrayList <T extends CallsForGrow>  // this works!
                              extends ArrayList<T> 

Für mich scheint es eine syntaktische Inkonsistenz zu sein. Aber vielleicht verstehe ich einige Finessen von Java 6 nicht? Gibt es noch andere Stellen, an denen ich Schnittstellen erweitern soll? Sollte die Schnittstelle, die ich erweitern möchte, einige Besonderheiten aufweisen?

Gangnus
quelle

Antworten:

25

Bei generischen Typvariablen ist es dem Compiler eigentlich egal, ob Tes sich um eine Klasse, eine Schnittstelle, eine Aufzählung oder eine Anmerkung handelt. Alles, was es interessiert, ist, dass es sich um einen Typ mit einer bestimmten Menge von Unter- und Supertypen handelt.

Und es gibt keinen Grund, die Syntax zu komplizieren, nur weil an einer anderen Stelle (an der Sie tatsächlich eine Schnittstelle implementieren) die Unterscheidung zwischen Klassen und Schnittstellen relevant ist (zum Beispiel, wenn Sie implementeine Schnittstelle sind, müssen Sie alle Methoden implementieren, die sie definiert, aber Sie brauchst du nicht, wenn du extendeine (nicht abstrakte) Klasse bist .

Angenommen, Sie implementsmüssten einen Moment lang hier schreiben , dann benötigen Sie auch eine separate Syntax für enumWerte (anstatt nur zu schreiben <E extends Enum<E>>) und Anmerkungen (die Sie einfach mit deklarieren können <A extends Annotation>).

Der einzige Ort, an dem Sie schreiben müssen , implementsist der Punkt, an dem Sie die Schnittstelle tatsächlich implementieren. An diesem Punkt (und nur an diesem Punkt) ist der Unterschied wichtig, da Sie die in der Schnittstelle definierten Methoden implementieren müssen. Für alle anderen spielt es keine Rolle, ob es sich Aum eine Basisklasse oder eine implementierte Schnittstelle von handelt B: Es ist ein Supertyp und das ist alles, was zählt.

Beachten Sie auch, dass Sie für extendsSchnittstellen einen anderen Ort verwenden :

interface A {
}

interface B extends A {
}

An dieser Stelle implementswäre das falsch, da B nicht umzusetzen A .

Joachim Sauer
quelle
Wenn wir Ihre Logik verwenden, sollten wir immer "Erweitert SomeInterface" verwenden , nicht nur bei Generika.
Gangnus
2
@Gangnus: nein, denn für den Implementierer gibt es einen konkreten Unterschied zwischen extendsund implements, nur wenn man das Problem aus der Perspektive eines reinen Typsystems betrachtet, gibt es keinen Unterschied.
Joachim Sauer
1
Entschuldigung, ich verstehe deinen Gedanken nicht. --1. Warum sollten wir in dem einen Fall "eine reine Typsystemperspektive" verwenden und nicht in dem anderen? --2. Warum ändern sich die syntaktischen Anforderungen an diesen verschiedenen Orten? Könnten Sie das bitte erklären? Wenn möglich in der Antwort.
Gangnus
1
@Gangnus: wer sagt das Tist eine klasse? Tkönnte auf einen Schnittstellentyp oder einen enumTyp verweisen .
Joachim Sauer
1
Von C # kommend ist diese ganze Diskussion lächerlich. Wir bezeichnen die Supertypen eines Typs mit :. Und im Hintergrund war und ist eine Schnittstelle eine abstrakte Klasse mit der Einschränkung, dass sie nur nicht implementierte virtuelle ( abstract) Mitglieder enthält, um Mehrfachvererbung zu ermöglichen. Es gibt buchstäblich keinen Unterschied zwischen implementsund extends. Sie könnten beide durch dasselbe Wort ( extends) oder durch ein beliebiges Symbol ( :) ersetzt werden und nichts würde verloren gehen.
Sara
5

Als Java 5, und insbesondere Generika, Entwicklern zur Verfügung gestellt wurde, die ein Interesse angemeldet hatten, war die Syntax ganz anders. Anstelle von Set<? extends Foo>und hatte Set<? super Bar>es Set<+Foo>und Set<-Foo>. Die Rückmeldung war jedoch, dass nicht klar war, ob +dies spezifischer oder umfassender gemeint war (mehr Klassen) . Sun reagierte auf dieses Feedback mit einer Änderung der Syntax, unter der Einschränkung, keine neuen Schlüsselwörter einzuführen, was ein Problem für die Abwärtskompatibilität gewesen wäre.

Das Ergebnis ist, dass beides nicht ganz natürlich ist. Wie Sie sehen, extendsist es überladen, von Klassen zu sprechen, die Schnittstellen "erweitern", was in anderen Kontexten nicht die Sprache ist. und superist überladen, um "ist eine Superklasse von" zu bedeuten, was die entgegengesetzte Richtung der Beziehung ist, die zuvor durch das Schlüsselwort ausgedrückt wurde, dh sich auf eine Superklasse bezieht.

Die Grundlagen einer Schnittstelle sind von dieser Änderung jedoch nicht betroffen, und es werden keine speziellen Schnittstellen eingeführt, die auf neue Weise erweitert werden.

Peter Taylor
quelle
+1. Ich sehe und stimme zu. Aber Joachim Sauer hat mein falsches Denken gefunden, dass T notwendigerweise eine Klasse ist. Die Antwort ist also seine. Dein Verständnis ist ein (oder zwei) Stockwerke höher :-). Mein Problem war primitiver. Trotzdem vielen Dank für meine Entwicklung.
Gangnus
2

Das Zulassen und Verbieten einer solchen Syntax hat Nachteile, und das Zulassen ist weitaus größer.

Man denke nur daran.

Die Trennung von Schnittstelle und Implementierung ist eine der grundlegenden Programmiersprachen. Aus diesem Grund ist die Syntax, die es erlaubt, "Interface implementiert etwas" zu buchstabieren , ungefähr so ​​schlecht wie die Verwendung eines Pluszeichens, um die Multiplikation von Operanden zu kennzeichnen .

Mücke
quelle
Okay. Also verstehe ich wirklich etwas nicht. Ich hielt es für sehr wahrscheinlich. Aber du hast das Problem überhaupt nicht erklärt, sorry. T ist eine Darstellung einer Klasse. Warum verwende ich an einer Stelle T extens und an einer anderen T implementiert?
Gangnus
@Gangnus in dem von Ihnen bereitgestellten Beispiel T bezieht sich auf Typparameter, die nicht unbedingt eine Klasse sind - siehe, was Joachim Ihnen bereits gesagt hat . Zulassen Geräte für sie würde auf die gleiche Chaos führen bereits erwähnt
gnat
Ja, ich habe schon seinen Kommentar gesehen. Es wird als Antwort markiert, wenn die Antwort eingegeben wird. Bis dahin haben Sie beide meinen Dank und +1.
Gangnus
-1

Man muss die schnittstellengesteuerte Programmierung als nächsten Schritt verstehen, während man eine Schnittstelle versteht. Hier erfahren Sie, wie die Benutzeroberfläche tatsächlich verwendet wird. Welche Rolle spielt es in einem Java-Programm (oder einer anderen Sprache)?

Deepak
quelle
2
Wie geht Ihre Antwort auf die Bedenken des OP ein? Bitte bearbeiten Sie Ihre Antwort, um sie klarer zu gestalten.