In Schnittstellen geschützt

111

Warum sind alle Methoden in einer interfaceDefinition implizit public? Warum erlaubt es keine protectedMethode?

Swaranga Sarma
quelle
22
Sehr gute Frage. Für fast alle anderen Dinge in Java habe ich einen echten Grund für die getroffenen Entscheidungen gefunden, aber für diesen habe ich keinen. Für mich ist es vollkommen sinnvoll, eine geschützte Methode in einer Schnittstelle zu definieren, die es einer anderen Klasse innerhalb desselben Pakets ermöglicht, diese Methode für ein implementierendes Objekt zu verwenden, ohne dass diese Methode verfügbar gemacht werden muss, die möglicherweise nicht von einer anderen Person als der aufgerufen werden soll Paketmitglieder an den Rest der Welt.
Markus A.
4
@ MarkusA. Schnittstellen funktionieren jedoch in beide Richtungen, dh sie können auch von Klassen außerhalb des aktuellen Pakets implementiert werden (und dann möglicherweise als Argumente an Methoden innerhalb dieses Pakets übergeben werden). Wie könnte eine Klasse von außerhalb des aktuellen Pakets "geschützte" Methoden einer öffentlichen Schnittstelle implementieren?
MartinStettner
8
@ MartinStettner: Das würde es nicht. Das wäre der Punkt. Ein Paket verfügt möglicherweise über mehrere nicht verwandte Klassen, die eine Schnittstelle implementieren, und möchte jedem Code, der eine Referenz dieses Schnittstellentyps erhält, garantieren, dass er sich auf eine bestimmte Weise verhält. Eine solche Garantie könnte erheblich verschärft werden, wenn verhindert werden könnte, dass externer Code behauptet, die Schnittstelle zu implementieren, während er sich vertragswidrig verhält.
Supercat
1
@ MarkusA. Wenn Sie einen guten Punkt angesprochen haben, sollten Sie ihn mit dem Modulsystem von Java 9
Nir Alfasi
1
Wenn die Schnittstelle über eine protectedMethode verfügt , werden alle implementierenden Klassen als Untertyp der Schnittstelle angesehen. Alle diese Klassen können auf geschützte Methoden zugreifen. macht es das protectedSchlüsselwort für die Methode nicht nutzlos? Solange wir keine Möglichkeiten haben, einzuschränken, wer dieses schnittstellengeschützte Schlüsselwort für die Methode implementiert, ist dies nutzlos. Korrigiere mich, wenn ich falsch liege!
Amarnath Harish

Antworten:

67

Weil eine Schnittstelle "was Sie von außerhalb der Klasse sehen können" bedeuten soll. Es wäre nicht sinnvoll, nicht öffentliche Methoden hinzuzufügen.

Raveline
quelle
16
Aber warum nicht Funktionen haben, die nur Mitglieder desselben Pakets wie die Schnittstelle "von außerhalb der Klasse sehen können"? Ich hatte mehrere Anwendungsfälle, in denen ich mir das gewünscht habe.
Markus A.
5
@ MarkusA. Mir ist klar, dass dies zu spät ist, aber dann können Sie eine vollständige abstract class, die alles interfaceist, erstellen und angeben, welchen Zugriff Sie möchten. Zugegeben, dies verliert den Vorteil mehrerer Implementierungen, interfacedie in Java verfügbar sind. Es wäre jedoch nicht testbar und verwirrend, ehrlich einen Vertrag zu schließen, der den Einschränkungen eines anderen Pakets entspricht, da Sie außerhalb dieses Pakets praktisch nicht auf die Methode Ihrer eigenen Implementierung zugreifen können .
Pickypg
10
@pickypg Wenn die Klasse, die die Schnittstelle implementieren würde, bereits eine andere Klasse erweitert, können Sie sie nicht dazu bringen, eine andere Klasse zu erweitern. Ich würde es nicht verwirrend finden für eine Schnittstelle, die nur innerhalb eines Pakets verwendet wird.
Flamma
24
@Raveline, -1, Dies wirft die Frage auf: "Warum soll eine Schnittstelle bedeuten, was Sie von außerhalb der Klasse sehen können?" Java 8 erlaubt bereits Methodenkörper in Schnittstellen. Warum also nicht auch geschützte abstrakte Methoden zulassen?
Pacerier
8
Ich habe diese Erklärung oft gelesen, aber meiner Meinung nach ist sie falsch. Eine Schnittstelle ist eine Art "Standard-Austauschprotokoll", unabhängig davon, ob es sich um OOP, Kommunikations-API oder Hardware handelt. Der USB-Anschluss an meinem PC ist eindeutig eine öffentliche Schnittstelle. Aber die Pins auf meinem Mainboard, die sich hinter einem Schlüsselgehäuse befinden und den Zugriff auf optionale USB-Anschlüsse ermöglichen, sind eindeutig eine "geschützte" Schnittstelle. Dann haben wir den BIOS-Chip - der ebenfalls eine standardisierte Schnittstelle ist, aber in keiner Weise veröffentlicht wird. Nur wenige Unternehmen kennen die genauen Details privat. Schnittstellen können also natürlich jede Sichtbarkeit haben! Warum nicht in OOP?
Foo Bar
55

Obwohl der oft zitierte Grund darin besteht, dass "Schnittstellen öffentliche APIs definieren", halte ich dies für eine übermäßige Vereinfachung. (Und es "riecht" auch nach zirkulärer Logik.)

Es wäre nicht bedeutungslos, Schnittstellen mit einer Mischung aus Zugriffsmodifikatoren zu haben. zB teilweise öffentlich und teilweise auf andere Klassen im selben Paket wie die Schnittstelle beschränkt. In einigen Fällen könnte dies sogar sehr nützlich sein, IMO.

Tatsächlich denke ich, dass der Grund für die implizite Veröffentlichung von Mitgliedern einer Schnittstelle darin besteht, dass die Java-Sprache dadurch einfacher wird :

  • Implizit öffentliche Schnittstellenmitglieder sind für Programmierer einfacher zu handhaben. Wie oft haben Sie Code (Klassen) gesehen, in dem die Methodenzugriffsmodifikatoren scheinbar zufällig ausgewählt wurden? Viele "normale" Programmierer haben Schwierigkeiten zu verstehen, wie Java-Abstraktionsgrenzen am besten verwaltet werden können 1 . Das Hinzufügen von public / protected / package-private zu Schnittstellen macht es für sie noch schwieriger.

  • Implizit öffentliche Schnittstellenmitglieder vereinfachen die Sprachspezifikation ... und damit die Aufgabe für Java-Compiler-Autoren und die Leute, die die Reflection-APIs implementieren.

Die Denkweise, dass die "Schnittstellen öffentliche APIs definieren", ist wohl eine Konsequenz (oder ein Merkmal) der vereinfachenden Entscheidung für das Sprachdesign ... nicht umgekehrt. In Wirklichkeit haben sich die beiden Gedankengänge in den Köpfen der Java-Designer wahrscheinlich parallel entwickelt.

In jedem Fall macht die offizielle Antwort auf die RFE in JDK-8179193 deutlich, dass das Java-Designteam entschieden hat 2 , dass das Zulassen protectedvon Schnittstellen die Komplexität erhöht und nur wenig wirklichen Nutzen bringt. Ein großes Lob an @skomisa für die Suche nach Beweisen .

Die Beweise in der RFE lösen das Problem. Das ist der offizielle Grund, warum das nicht hinzugefügt wurde.


1 - Natürlich haben Top-Gun-Programmierer keine Schwierigkeiten mit diesen Dingen und begrüßen möglicherweise eine umfangreichere Palette von Zugriffssteuerungsfunktionen. Aber was passiert, wenn der Code zur Pflege an eine andere Person übergeben wird?

2 - Sie können mit ihrer Entscheidung oder ihrer Begründung nicht einverstanden sein, aber das ist strittig.

Stephen C.
quelle
21

Ich muss sagen, dass diese Frage durch die Einführung von Standardmethoden in Java 8 erneut geöffnet wurde. Das Projekt, an dem ich gerade arbeite, soll, ähnlich wie die Basis einer Schnittstelle, die Absicht von der Implementierung abstrahieren.

Es gibt mehrere Fälle, in denen ich meinen Code mit einer "standardmäßig geschützten" Methode drastisch vereinfachen könnte. Es stellt sich heraus, dass dies nicht wirklich funktioniert, da die Schnittstellen immer noch an der Java 7-Logik festhalten. Eine normale geschützte Methode macht aus den oben genannten Gründen keinen besonderen Sinn. Wenn jedoch eine öffentliche Standardmethode eine Ressource auf niedriger Ebene erfordert, die sich wahrscheinlich nicht ändert und von einer geschützten Methode bereitgestellt werden kann, scheint es mir, dass eine "standardmäßig geschützte" Arbeit nicht nur saubereren Code aufrechterhält, sondern auch zukünftige Benutzer schützt versehentlicher Missbrauch.

(Dies ändert tragischerweise nichts an der Tatsache, dass ich meinen Code immer noch mit ansonsten unnötigen Abstracts überkomplizieren muss; ich beabsichtige jedoch, eine Funktionsanforderung bei Oracle einzureichen.)

Michael Oberlin
quelle
Ich stimme zu 100% zu%. Abstrakte Klassen waren vor der Einführung von Standardmethoden eine sinnvolle Alternative. Die Einschränkungen, die sie der Mehrfachvererbung auferlegen, bedeuten jedoch, dass sie nicht perfekt sind. Schnittstellen mit Standardmethoden sind normalerweise eine bessere Alternative in einer> = JDK 1.8-Welt. Da sie jedoch keinen Status speichern können, müssen andere abstrakte Methoden definiert werden, um den Status verfügbar zu machen. Dies bedeutet, dass der Status veröffentlicht wird, was nicht immer der Fall ist Sie wollen.
Pater Jeremy Krieg
10

Weil Schnittstellen öffentliche APIs definieren. Alles, was geschützt ist, ist ein internes Detail, das nicht zu einer Schnittstelle gehört.

Sie können abstrakte Klassen mit geschützten abstrakten Methoden verwenden, aber die Schnittstellen sind auf öffentliche Methoden und öffentliche statische Endfelder beschränkt.

Sean Patrick Floyd
quelle
5
Sie haben angegeben, "weil Schnittstellen öffentliche APIs definieren". Was ist der Grund, warum Schnittstellen nur publicAPIs definieren sollten ? Es gibt einen Unterschied zwischen "internen Details" und "Implementierungsdetails". protectedIn Java handelt es sich definitiv nicht um interne Details, da es sich nun um eine öffentliche Schnittstelle handelt, die für alle veröffentlicht wird, die sie unterordnen können. Dies ist im Grunde die ganze Welt.
Pacerier
1
Nicht mehr wahr mit den Standardmethoden von Java 8.
Mario Rossi
@MarioRossi Und auch nicht mehr wahr mit den privaten Schnittstellenmethoden von Java 9.
Skomisa
7

Vielleicht, weil es sich um eine Schnittstelle handelt , dh um Kunden zu sagen, was sie mit Instanzen tun können, anstatt ihnen zu sagen, was sie nicht können.

Ingo
quelle
1
Ich verstehe nicht, warum eine Schnittstelle Unterklassen nicht auch sagen kann, was sie tun können, ohne diese Implementierung der Außenwelt auszusetzen. Dies war eine Entwurfsentscheidung, die zu einer Zeit getroffen wurde, als abstrakte Klassen als perfekte Alternative verwendet werden konnten. Mit dem Aufkommen von Standardmethoden in Schnittstellen sind abstrakte Klassen nun eine unvollständige Alternative.
Pater Jeremy Krieg
6

Ich bin der festen Überzeugung, dass Schnittstellen geschützte Methoden zulassen sollten. Wer hat gesagt, dass Schnittstellen für alle auf der ganzen Welt sichtbar sein müssen? Was Ihren Punkt betrifft, dass es "normale" (sprich: inkompetente) Programmierer verwirren könnte: Bei so viel OOP geht es darum, Objekte, Klassen, Pakete usw. richtig zu strukturieren. Wenn es einem Programmierer schwer fällt, all das richtig zu machen, hat er eine viel größeres Problem. Java wurde gebaut für diese Art der Sache.

IntelliData
quelle
Dies beantwortet die Frage nicht.
Stephen C.
5

Einige Antworten hier verwenden Zirkelschlussfolgerungen, um zu erklären, warum Schnittstellenmethoden nicht geschützt werden können: Sie müssen öffentlich sein, also können sie offensichtlich nicht geschützt werden!

Das erklärt nichts, aber glücklicherweise hat jemand vor ein paar Jahren eine Erweiterungsanforderung für geschützte Methoden in Schnittstellen als JDK-Fehler gestellt , die etwas Licht in das Problem bringt:

Geschützte Methoden in Schnittstellen: Paketübergreifend

Da Modifikatoren in Java etwas eingeschränkt sind, ist die Möglichkeit, Methoden paketübergreifend gemeinsam zu nutzen, auf öffentliche Methoden beschränkt. Manchmal ist es gefährlich, eine Methode öffentlich zu machen, aber es muss daran liegen, dass keine geeigneten Modifikatoren vorhanden sind. Meine Lösung überwindet diese Einschränkung.

Die Java-Sprachspezifikation erlaubt derzeit nicht den geschützten Modifikator für Schnittstellenmethoden. Wir können diese Tatsache ausnutzen und für diese neue Funktion geschützte Schnittstellenmethoden verwenden.

Wenn eine Schnittstellenmethode als geschützt markiert ist und die Schnittstelle von einer Klasse in einem anderen Paket implementiert wird, muss die Methode nicht öffentlich sein, sondern kann auch privat oder zumindest paketgeschützt sein. Die Methode ist sichtbar, was auch immer die Klasse deklariert, und zusätzlich im Quellpaket der Schnittstelle (und in den Unterpaketen?) Sichtbar.

Auf diese Weise könnten wir bestimmte Methoden für bekannte Pakete freigeben.

Und dies ist die Antwort auf diese Erweiterungsanforderung, die mit dem Status geschlossen wurde Won't fix:

Dieser Vorschlag versucht, ein Problem auf eine Weise zu lösen, die Komplexität und Sonderfälle für wenig tatsächlichen Gewinn hinzufügt. Ein typischer Weg, um dieses Problem zu lösen, besteht darin, eine private Klasse zu haben, die eine öffentliche Schnittstelle implementiert. Die Implementierungsmethoden sind öffentlich, befinden sich jedoch in einer privaten Klasse, sodass sie privat bleiben.

Eine Alternative, die ab Java 9 verfügbar ist, besteht darin, Klassen und Methoden öffentlich zu machen, jedoch innerhalb eines Moduls, das einen qualifizierten Export in bestimmte "Freund" -Module aufweist, anstatt in die allgemeine Öffentlichkeit exportiert zu werden.

Die maßgeblichen Erkenntnisse aus diesem Fehlerbericht sind also:

  • Die aktuelle Situation wird sich nicht ändern. Es ist unwahrscheinlich, dass Schnittstellen jemals protectedMethoden unterstützen.
  • Die Rechtfertigung dafür, protectedMethoden in Schnittstellen nicht zu unterstützen , ist, dass sie " Komplexität und Sonderfälle für geringen tatsächlichen Gewinn hinzufügen ".
  • Seit Java 9 gibt es einen alternativen Ansatz für den Zugriff auf Methoden auf Paketebene. Verwenden Sie das Java Platform Module System (JPMS), um " Klassen und Methoden öffentlich zu machen, jedoch innerhalb eines Moduls, das einen qualifizierten Export in bestimmte" Freund "-Module aufweist, anstatt in die allgemeine Öffentlichkeit exportiert zu werden ".
Skomisa
quelle
4

Da eine implementierende Klasse ALLE in Ihrer Schnittstelle deklarierten Methoden implementieren muss, was würde passieren, wenn sich Ihre implementierende Klasse in einem anderen Paket befindet?

dm76
quelle
2

Schnittstelle Wenn Sie etwas verwenden möchten, wie Sie es beschrieben haben, fahren Sie mit abstrakten Klassen oder verschachtelten Schnittstellen fort.

Ein Auszug aus dem Code - Stil über Schnittstellenvariablen, sondern gilt immer noch zu Methoden aber:

Schnittstellenvariablen sind implizit öffentlich, da Schnittstellen eine Anwendungsprogrammierschnittstelle (Application Programming Interface, API) bereitstellen sollen, auf die Java-Programmierer vollständig zugreifen können, um sie in ihren eigenen Anwendungen zu referenzieren und zu implementieren. Da eine Schnittstelle in Java-Paketen verwendet werden kann, die sich von ihren eigenen unterscheiden, stellt die öffentliche Sichtbarkeit sicher, dass Programmcode auf die Variable zugreifen kann.
Grizzly
quelle
2

Das Deklarieren interner Subschnittstellen ist eine gute Vorgehensweise, Sie können Ihre internen Methoden jedoch nicht als deklarieren protected technisch in einer Schnittstelle in Java .

Natürlich können Sie eine andere Schnittstelle für den internen Gebrauch erstellen, die die öffentliche Schnittstelle erweitert:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

Sie können die InternalInterfaceSchnittstelle innerhalb des Pakets verwenden, sollten jedoch einen beliebigen Subtyp von PublicInterface(in öffentlichen Methoden) akzeptieren :

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Außerhalb des Pakets können Benutzer PublicInterfaceproblemlos verwenden.

Normalerweise erstellen Programmierer abstrakte Klassen in ähnlichen Situationen. In diesem Fall verlieren wir jedoch die Vorteile der Mehrfachvererbung.

Dávid Horváth
quelle
1
Außerhalb des Pakets können Benutzer auch verwenden YourPublicInterface.Internal. Alles in einer Schnittstelle, einschließlich verschachtelter Schnittstellen, ist unabhängig vom Vorhandensein oder Fehlen des publicSchlüsselworts öffentlich .
Greg Roelofs
1

Das einzige Szenario, in dem es sinnvoll wäre, wenn Sie die Sichtbarkeit auf dasselbe Paket beschränken möchten. Alle anderen Verwendungen von protectedsind nicht anwendbar. Insbesondere protectedwerden häufig Methoden verwendet, um Nachkommen Zugriff auf einige Details von Implementierungen auf niedrigerer Ebene zu gewähren. Es ist jedoch nicht sinnvoll, dies in einer Schnittstelle zu deklarieren, da keine Implementierung auf niedrigerer Ebene verfügbar gemacht werden muss.

Und selbst das Paketszenario ist nicht wirklich das, worum es bei Schnittstellen geht.

Um das zu erreichen, was Sie wahrscheinlich wollen, benötigen Sie zwei Schnittstellen, eine für den internen Gebrauch und eine, die Sie in der öffentlichen API verfügbar machen. (Mit der internen möglicherweise, aber nicht unbedingt der öffentlichen.) Oder, wie andere betonten, einer abstrakten Oberklasse.

biziclop
quelle
Eine abstrakte Oberklasse kann verhindern, dass sie von Typen außerhalb ihres Pakets abgeleitet wird. Jemand, der eine Referenz eines solchen Superklassentyps erhält und dem Autor des Pakets vertraut, kann sicher sein, dass sich das Objekt wie behauptet verhält. Wenn ein Paket mehrere Klassen hat, die einige allgemeine Funktionen verfügbar machen möchten, aber nicht in eine richtige Hierarchie passen (z. B. eine implementiert die Funktionen X und Y, ein Y und Z sowie ein X und Z), wäre es hilfreich, wenn es verfügbar machen könnte Die Funktionalität unter Verwendung von Schnittstellen verspricht zwar immer noch, dass Instanzen, auf die von den Schnittstellentypen verwiesen wird, "echt" sind.
Supercat
0

Auf geschützte Methoden kann die Unterklasse immer nur zugreifen, wenn die Unterklasse die Basisklasse erweitert.

Im Falle einer Schnittstelle erweitert die Unterklasse die Schnittstelle niemals. Es implementiert die Schnittstelle.

Geschützte Methoden sind über Extend und nicht mit Implement zugänglich .

Aftaab Siddiki
quelle
Welcher Unterschied welches Schlüsselwort, spielt keine Rolle.
Alex78191
0

Schnittstellen sollen Methoden der Außenwelt aussetzen . Daher sind diese Methoden von Natur aus öffentlich. Wenn Sie jedoch Abstraktion innerhalb derselben Klassenfamilie einführen möchten, können Sie eine andere Abstraktionsebene zwischen Ihrer Schnittstelle und der Implementierungsklasse erstellen, dh eine abstrakte Klasse. Ein Beispiel ist unten gezeigt.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}
Stefanos Kargas
quelle
2
Aber private Methoden, die niemand sehen wird, sind in den Schnittstellen erlaubt.
Alex78191
Java verfügt über Standardmethoden in Schnittstellen, dh eine Schnittstelle ist eine Krücke, um die Mehrfachvererbung abstrakter Klassen zu umgehen. Dann sei die Mehrfachvererbung abstrakter Klassen erlaubt. Konflikte mit Standardmethoden wurden nicht zum Problem.
Alex78191
Du hast recht. Ab Java 9 sind private Methoden in Schnittstellen zulässig. Diese können nicht abstrakt sein und werden innerhalb der Schnittstelle implementiert und verwendet, hauptsächlich durch andere Standard- oder statische Methoden (wenn sie selbst statisch sind).
Stefanos Kargas
1
Diese Antwort ignoriert einfach die gestellte Frage: Warum können Schnittstellen keine geschützten Methoden haben? Geschützte Methoden würden immer noch "Methoden der Außenwelt aussetzen" , und die Behauptung, dass "diese Methoden von Natur aus öffentlich sind", ist einfach falsch. Sie sind öffentlich, weil die Sprache so entworfen wurde, aber sie hätte geschützte Methoden in Schnittstellen zulassen können. Das OP fragt einfach warum.
Skomisa