Warum gibt es in Java keinen Sichtbarkeitsmodifikator für Unterklassen?

74

Bei mehr als einer Gelegenheit habe ich mir eine variable Sichtbarkeit gewünscht, die in Java nicht möglich ist. Ich wollte, dass bestimmte Mitglieder innerhalb ihrer eigenen Klasse und innerhalb von Unterklassen sichtbar sind, aber nicht für den Rest des Pakets oder für den Rest der Welt. Mit anderen Worten, ich wollte das:

Modifier        Class     Package   Subclass  World
sub-class       Y         N         Y         N

Die Entwickler von Java Allerdings gab nur mir dies :

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N

Der typische Fall, wenn ich so etwas möchte, ist das Erstellen einer abstrakten Klasse. Manchmal finde ich, dass der abstrakte Elternteil Zugang zu bestimmten Mitgliedern benötigt, aber auch konkrete Kinder. Ich kann ihnen diesen Zugang gewähren, indem ich die Mitglieder mache protected, aber das eröffnet den Zugang zum Rest des Pakets, wenn ich nicht wirklich will.

Um ganz klar zu sein, ich weiß, dass ein solcher Modifikator in Java nicht möglich ist. Meine Frage ist, warum ein solcher Modifikator nicht in Java enthalten ist. Es scheint (für mich) eine natürlichere Sichtbarkeitsstufe zu sein als entweder protectedoder die Standardeinstellung. Ist der Grund dafür nicht wichtig genug, um aufgenommen zu werden, oder hängt er eher mit möglichen Nebenwirkungen zusammen, die ich nicht berücksichtigt habe?

Michael McGowan
quelle
1
Um dieses Problem zu umgehen, können Sie die Variablen privat machen und dann eine statische innere Klasse verwenden, um dies zu erreichen.
Jeff Foster
1
Vielleicht, weil normalerweise Leute Unterklassen erstellen, die in einem anderen Paket als die Eltern leben? Ein typisches Beispiel ist die Erweiterung von Bibliotheken von Drittanbietern, um unsere eigene Implementierung bereitzustellen.
Adarshr
1
@adarshr: Das ist der genaue Grund für die Existenz eines Unterklassenmodifikators. Wenn alle Unterklassen im selben Paket wie die Superklasse wären, würde es sich nicht von geschützt unterscheiden.
Aioobe
5
Wie es passiert hatte Java 1.0 private protected. Ich glaube, die Implementierung war fehlerhaft. In 1.1 fallen gelassen.
Tom Hawtin - Tackline
4
Ich vermisse diese Sichtbarkeit auch aus den gleichen Gründen wie @Michael. Es fühlt sich irgendwie "unnötig" an, meine Klassen in einem separaten Paket (abstrakte Oberklasse und konkrete Unterklassen) zusammenzufassen, um die Sichtbarkeit einzuschränken. Auch solche hackigen Lösungen wie das Konkretisieren von Superklassen als private Mitgliedsvariable in Unterklassen, das Implementieren einer Schnittstelle usw. machen den Code komplizierter als er sollte. privat geschützt würde die Dinge wirklich schöner machen, indem die Kapselung während des Erbens auf die geringste Komplexität gebracht wird.
Robert

Antworten:

19

Ich nehme an, sie möchten die zusätzliche Komplexität vermeiden, indem sie eine nichtlineare Zugriffshierarchie haben.

Sie sollten die Kontrolle über Ihr Paket haben, also rufen Sie diese geschützten Methoden dort einfach nicht auf.

( Ist übrigens protectednicht ganz dasselbe wie sub-class and package, da nicht statisch geschützte Methoden (wenn nicht im selben Paket) nicht für beliebige Objekte der deklarierenden Klasse aufgerufen werden können, sondern nur für Objekte der Unterklasse, in der sich der Code befindet (Sie können dies sehen Object.clone(), das nur von der Klasse aufgerufen werden kann, deren Objekt geklont wird.))

Paŭlo Ebermann
quelle
Ich verstehe Ihren Kommentar in Klammern nicht. geschützt ist die Sichtbarkeit der Unterklasse + die Sichtbarkeit des Pakets. Was meinst du?
ewernli
1
@ewernli protectedist ein bisschen weniger. Obwohl jede Klasse von erbt Object(dh clone()überall sichtbar sein sollte), können Sie kein anyObject.clone()beliebiges Objekt aufrufen .
Paŭlo Ebermann
1
In ähnlicher Weise kann jede Instanz einer Klasse auf die privateMitglieder einer anderen Instanz derselben Klasse zugreifen . Sie würden denken, weil ein Mitglied ist private, sollte nur diese Instanz darauf zugreifen können, aber wie @ PaŭloEbermann sagte, hätten Sie bereits die volle Kontrolle über die Klasse. Wenn Sie auf privateMitglieder einer anderen Instanz zugreifen , liegt dies daran, dass Sie sie so entworfen haben. Wenn Sie ein Paket entwickeln und auf ein protectedMitglied einer anderen Klasse zugreifen , liegt dies daran, dass Sie derjenige sind, der dieses Paket entwickelt, auf das andere keinen Zugriff haben.
Michael Plautz
Alte Kommentare / Frage zu Kommentar, aber kann jemand die Aussage klarstellen - "Sie sollten die Kontrolle über Ihr Paket haben"? Wenn ich eine Bibliothek eines Drittanbieters habe, kann ich jederzeit ein Paket mit derselben Hierarchie erstellen und bei Bedarf auf die geschützten Mitglieder zugreifen. Ist das nicht der Fall?
Mubin
@Mubin Dies ist der Fall, ja (wenn es keinen Sicherheitsmanager gibt, der einschränkt, welcher Klassenlader Klassen in einem Paket erstellen kann). Sie können aber auch eine modifizierte Version Ihrer Drittanbieter-Bibliothek erstellen und private Mitglieder öffentlich machen. Oder verwenden Sie Reflexion. Alle diese Zugriffsmodifikatoren sind überhaupt nicht wasserdicht.
Paŭlo Ebermann
9

Im selben Paket zu sein, wird einfach als engere Beziehung angesehen als ein Subtyp zu sein .

Warum?

Normalerweise steuern Sie den gesamten Quellcode des Pakets, das Sie entwickeln (*) , sodass Sie zumindest die Möglichkeit haben , fehlerhafte Aufrufe zu vermeiden.

Sie steuern nicht den gesamten Code, der Ihre Klassen erweitert. (Jeder kann Ihre Klasse erweitern.) Dies bedeutet, dass der private Paketzugriff eine wichtigere Rolle spielt.


*) Aber hey, ich starte jede Quelldatei mit, package com.yourpackage;damit du nicht den gesamten Code in deinem Paket kontrollierst! Nun ja, aber a) das solltest du eigentlich nicht tun und b) es kann durch Versiegeln der Verpackungen verhindert werden .

aioobe
quelle
Ich kann mich nicht entscheiden, welche Beziehung meiner Meinung nach enger ist. Mein Instinkt war, dass das Sein eines Subtyps eine engere Beziehung war (und vielleicht ist das ein Teil des Grundes, warum ich denke, dass diese Art von Modifikator sinnvoller ist als geschützt und standardmäßig). Ein zufälliger Codierer, der eine von mir erstellte JAR-Bibliothek verwendet, kann jedoch eine meiner Klassen unterordnen, während ich wahrscheinlich weiß, was in meinem Paket vor sich geht. Hmmm ...
Michael McGowan
Ja. Genau ich denke auch darüber nach. Und Sie könnten sogar "wahrscheinlich" in Ihrem letzten Satz zuschlagen, wenn Sie das Paket versiegeln .
Aioobe
Ich habe Schwierigkeiten, mir ein Szenario vorzustellen, in dem Sie kein versiegeltes Paket wünschen würden.
CorsiKa
3

Sie sollten Ihre Klasse in ein eigenes Paket einfügen und das Mitglied (Instanzvariable oder Methode) als geschützt markieren. Auf diese Weise können keine anderen Klassen außer den Unterklassen auf das Mitglied zugreifen, das Sie als geschützt vermarkten. Sie erhalten eine Klasse in einem Paket, wenn Sie nur möchten, dass nur Unterklassen auf dieses geschützte Mitglied zugreifen.

Hampelmann
quelle