Ich habe festgestellt, dass äußere Klassen auf private Instanzvariablen innerer Klassen zugreifen können. Wie ist das möglich? Hier ist ein Beispielcode, der dasselbe demonstriert:
class ABC{
class XYZ{
private int x=10;
}
public static void main(String... args){
ABC.XYZ xx = new ABC().new XYZ();
System.out.println("Hello :: "+xx.x); ///Why is this allowed??
}
}
Warum ist dieses Verhalten erlaubt?
new ABC().new XYZ()
Antworten:
Die innere Klasse ist nur eine Möglichkeit, einige Funktionen, die wirklich zur ursprünglichen äußeren Klasse gehören, sauber zu trennen. Sie sollen verwendet werden, wenn Sie zwei Anforderungen haben:
Angesichts dieser Anforderungen haben innere Klassen vollen Zugriff auf ihre äußere Klasse. Da sie im Grunde ein Mitglied der äußeren Klasse sind, ist es sinnvoll, dass sie Zugriff auf Methoden und Attribute der äußeren Klasse haben - einschließlich privater.
quelle
Wenn Sie die privaten Mitglieder Ihrer inneren Klasse ausblenden möchten, können Sie eine Schnittstelle mit den öffentlichen Mitgliedern definieren und eine anonyme innere Klasse erstellen, die diese Schnittstelle implementiert. Beispiel unten:
quelle
x
nicht erlaubt, wenn es hier öffentlich istmMember.x
.Die innere Klasse wird (zum Zwecke der Zugriffskontrolle) als Teil der enthaltenden Klasse betrachtet. Dies bedeutet vollen Zugriff auf alle Privaten.
Die Implementierung erfolgt mithilfe synthetischer paketgeschützter Methoden: Die innere Klasse wird in einer separaten Klasse im selben Paket (ABC $ XYZ) kompiliert. Die JVM unterstützt diese Isolationsstufe nicht direkt, sodass ABC $ XYZ auf Bytecode-Ebene über paketgeschützte Methoden verfügt, mit denen die äußere Klasse zu den privaten Methoden / Feldern gelangt.
quelle
Auf eine ähnliche Frage wird eine richtige Antwort angezeigt: Warum kann auf das private Mitglied einer verschachtelten Klasse mit den Methoden der einschließenden Klasse zugegriffen werden?
Es heißt, es gibt eine Definition des privaten Scoping in JLS - Ermittlung der Zugänglichkeit :
quelle
Ein meiner Meinung nach wichtiger Anwendungsfall für innere Klassen ist das Fabrikmuster. Die einschließende Klasse kann eine Instanz der inneren Klasse ohne Zugriffsbeschränkungen vorbereiten und die Instanz an die Außenwelt weitergeben, wo der private Zugriff anerkannt wird.
Im Gegensatz zu deyx, das die Klasse statisch deklariert, werden die Zugriffsbeschränkungen für die einschließende Klasse nicht geändert, wie unten gezeigt. Auch die Zugriffsbeschränkungen zwischen statischen Klassen in derselben umschließenden Klasse funktionieren. Ich war überrascht ...
quelle
Zugriffsbeschränkungen werden pro Klasse vorgenommen. Es gibt keine Möglichkeit für eine in einer Klasse deklarierte Methode, nicht auf alle Instanz- / Klassenmitglieder zuzugreifen. Es liegt auf der Hand, dass innere Klassen auch uneingeschränkten Zugang zu den Mitgliedern der äußeren Klasse haben und die äußere Klasse ungehinderten Zugang zu den Mitgliedern der inneren Klasse hat.
Indem Sie eine Klasse in eine andere Klasse einfügen, ist sie eng mit der Implementierung verbunden, und alles, was Teil der Implementierung ist, sollte Zugriff auf die anderen Teile haben.
quelle
Die Logik hinter inneren Klassen besteht darin, dass, wenn Sie eine innere Klasse in einer äußeren Klasse erstellen, diese einige Dinge gemeinsam nutzen müssen und es daher sinnvoll ist, dass sie flexibler sind als "normale" Klassen.
Wenn es in Ihrem Fall keinen Sinn macht, dass die Klassen das Innenleben des anderen sehen können - was im Grunde bedeutet, dass die innere Klasse einfach zu einer regulären Klasse hätte gemacht werden können, können Sie die innere Klasse als deklarieren
static class XYZ
. Verwendenstatic
bedeutet, dass sie keinen gemeinsamen Status haben (und beispielsweisenew ABC().new XYZ()
nicht funktionieren, und Sie müssen ihn verwendennew ABC.XYZ()
.Wenn dies jedoch der Fall ist, sollten Sie darüber nachdenken, ob es
XYZ
sich wirklich um eine innere Klasse handelt und ob sie möglicherweise ihren eigenen verdient Manchmal ist es sinnvoll, eine statische innere Klasse zu erstellen (z. B. wenn Sie eine kleine Klasse benötigen, die eine Schnittstelle implementiert, die Ihre äußere Klasse verwendet, und die sonst nirgendwo hilfreich ist). Aber in etwa der Hälfte der Fälle es sollte eine äußere Klasse gemacht worden sein.quelle
Thilo hat eine gute Antwort auf Ihre erste Frage "Wie ist das möglich?" Hinzugefügt . Ich möchte auf die zweite gestellte Frage etwas näher eingehen: Warum ist dieses Verhalten zulässig?
Lassen Sie uns zunächst klarstellen, dass dieses Verhalten nicht auf innere Klassen beschränkt ist, die per Definition nicht statische verschachtelte Typen sind. Dieses Verhalten ist für alle verschachtelten Typen zulässig, einschließlich verschachtelter Aufzählungen und Schnittstellen, die statisch sein müssen und keine umschließende Instanz haben dürfen. Grundsätzlich ist das Modell eine Vereinfachung bis auf die folgende Aussage: Verschachtelter Code hat vollen Zugriff auf umschließenden Code - und umgekehrt.
Warum also? Ich denke, ein Beispiel veranschaulicht den Punkt besser.
Denken Sie an Ihren Körper und Ihr Gehirn. Wenn Sie Heroin in Ihren Arm injizieren, wird Ihr Gehirn hoch. Wenn die Amygdala-Region Ihres Gehirns erkennt, was seiner Meinung nach eine Bedrohung für Ihre persönliche Sicherheit darstellt, beispielsweise eine Wespe, wird er Ihren Körper dazu bringen, sich umzudrehen und auf die Hügel zu rennen, ohne dass Sie zweimal darüber nachdenken.
Das Gehirn ist also ein wesentlicher Bestandteil des Körpers - und seltsamerweise auch umgekehrt. Durch die Verwendung der Zugriffskontrolle zwischen solchen eng verbundenen Unternehmen verfällt ihr Anspruch auf Beziehung. Wenn Sie eine Zugriffskontrolle benötigen, müssen Sie die Klassen stärker in wirklich unterschiedliche Einheiten unterteilen. Bis dahin sind sie die gleiche Einheit. Ein treibendes Beispiel für weitere Studien wäre, zu untersuchen, wie ein Java
Iterator
normalerweise implementiert wird.Der uneingeschränkte Zugriff von eingeschlossenem Code auf verschachtelten Code macht es größtenteils ziemlich nutzlos, Zugriffsmodifikatoren zu Feldern und Methoden eines verschachtelten Typs hinzuzufügen. Dies führt zu Unordnung und kann für Neueinsteiger der Java-Programmiersprache ein falsches Sicherheitsgefühl darstellen.
quelle
Die innere Klasse wird als Attribut der äußeren Klasse angesehen. Unabhängig davon, ob die Instanzvariable der inneren Klasse privat ist oder nicht, kann die äußere Klasse problemlos auf sie zugreifen, genau wie auf ihre anderen privaten Attribute (Variablen).
quelle
Weil sich Ihre
main()
Methode in derABC
Klasse befindet, die auf ihre eigene innere Klasse zugreifen kann .quelle
ABC
Klasse auf in derABC
Klasse verschachtelte Klassen zugreifen können , sondern warum sie auf private Mitglieder von Klassen zugreifen können, die in derABC
Klasse in Java verschachtelt sind .