Was ist der Hauptunterschied zwischen einer inneren Klasse und einer statisch verschachtelten Klasse in Java? Spielt Design / Implementierung eine Rolle bei der Auswahl einer dieser Optionen?
Was ist der Hauptunterschied zwischen einer inneren Klasse und einer statisch verschachtelten Klasse in Java? Spielt Design / Implementierung eine Rolle bei der Auswahl einer dieser Optionen?
Antworten:
Aus dem Java-Tutorial :
Verschachtelte Klassen werden in zwei Kategorien unterteilt: statisch und nicht statisch. Verschachtelte Klassen, die als statisch deklariert sind, werden einfach als statische verschachtelte Klassen bezeichnet. Nicht statische verschachtelte Klassen werden als innere Klassen bezeichnet.
Auf statisch verschachtelte Klassen wird unter Verwendung des umschließenden Klassennamens zugegriffen:
OuterClass.StaticNestedClass
Verwenden Sie beispielsweise diese Syntax, um ein Objekt für die statisch verschachtelte Klasse zu erstellen:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Objekte, die Instanzen einer inneren Klasse sind, existieren innerhalb einer Instanz der äußeren Klasse. Betrachten Sie die folgenden Klassen:
class OuterClass {
...
class InnerClass {
...
}
}
Eine Instanz von InnerClass kann nur innerhalb einer Instanz von OuterClass vorhanden sein und hat direkten Zugriff auf die Methoden und Felder der umschließenden Instanz.
Um eine innere Klasse zu instanziieren, müssen Sie zuerst die äußere Klasse instanziieren. Erstellen Sie dann das innere Objekt innerhalb des äußeren Objekts mit folgender Syntax:
OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Siehe: Java-Lernprogramm - Verschachtelte Klassen
Der Vollständigkeit halber sei angemerkt, dass es auch eine innere Klasse ohne umschließende Instanz gibt :
class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}
Hier new A() { ... }
ist eine innere Klasse in einem statischen Kontext definiert und hat keine einschließende Instanz.
import OuterClass.StaticNestedClass;
Verweisen Sie dann auf die Klasse genauso wie auf OuterClass.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
?
Das Java-Tutorial sagt :
Terminologie: Verschachtelte Klassen werden in zwei Kategorien unterteilt: statisch und nicht statisch. Verschachtelte Klassen, die als statisch deklariert sind, werden einfach als statische verschachtelte Klassen bezeichnet. Nicht statische verschachtelte Klassen werden als innere Klassen bezeichnet.
Im allgemeinen Sprachgebrauch werden die Begriffe "verschachtelt" und "inner" von den meisten Programmierern synonym verwendet, aber ich werde den korrekten Begriff "verschachtelte Klasse" verwenden, der sowohl innere als auch statische Begriffe abdeckt.
Klassen können ad infinitum verschachtelt werden , z. B. kann Klasse A Klasse B enthalten, die Klasse C enthält, die Klasse D enthält usw. Es ist jedoch selten, dass mehr als eine Ebene der Klassenverschachtelung vorhanden ist, da es sich im Allgemeinen um ein schlechtes Design handelt.
Es gibt drei Gründe, warum Sie eine verschachtelte Klasse erstellen könnten:
In Java gibt es vier Arten verschachtelter Klassen . Kurz gesagt, sie sind:
Lassen Sie mich näher darauf eingehen.
Statische Klassen sind am einfachsten zu verstehen, da sie nichts mit Instanzen der enthaltenen Klasse zu tun haben.
Eine statische Klasse ist eine Klasse, die als statisches Mitglied einer anderen Klasse deklariert ist. Genau wie andere statische Mitglieder ist eine solche Klasse nur ein Aufhänger, der die enthaltende Klasse als Namespace verwendet, z. B. die Klasse Goat , die im Paket pizza als statisches Mitglied der Klasse Rhino deklariert ist, ist unter dem Namen pizza.Rhino.Goat bekannt .
package pizza;
public class Rhino {
...
public static class Goat {
...
}
}
Ehrlich gesagt sind statische Klassen eine ziemlich wertlose Funktion, da Klassen bereits durch Pakete in Namespaces unterteilt sind. Der einzig denkbare Grund, eine statische Klasse zu erstellen, besteht darin, dass eine solche Klasse Zugriff auf die privaten statischen Mitglieder ihrer enthaltenden Klasse hat, aber ich finde, dass dies eine ziemlich lahme Rechtfertigung für das Vorhandensein der statischen Klassenfunktion ist.
Eine innere Klasse ist eine Klasse, die als nicht statisches Mitglied einer anderen Klasse deklariert ist:
package pizza;
public class Rhino {
public class Goat {
...
}
private void jerry() {
Goat g = new Goat();
}
}
Wie bei einer statischen Klasse wird die innere Klasse durch ihren enthaltenden Klassennamen pizza.Rhino.Goat als qualifiziert bezeichnet , aber innerhalb der enthaltenden Klasse kann sie unter ihrem einfachen Namen erkannt werden. Jedoch wird jede Instanz einer inneren Klasse auf eine bestimmte Instanz der umschließenden Klasse gebunden: oben, die Ziege in erstellt Jerry , wird implizit zur gebundenen Rhino - Instanz dies in Jerry . Andernfalls machen wir die zugehörige Rhino- Instanz explizit, wenn wir Goat instanziieren :
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(Beachten Sie, dass Sie den inneren Typ in der seltsamen neuen Syntax nur als Ziege bezeichnen : Java leitet den enthaltenen Typ aus dem Nashorn- Teil ab. Und ja, neues Nashorn . Goat () hätte auch für mich mehr Sinn gemacht.)
Was bringt uns das? Nun, die innere Klasseninstanz hat Zugriff auf die Instanzmitglieder der enthaltenden Klasseninstanz. Diese einschließenden Instanzmitglieder werden innerhalb der inneren Klasse nur über ihre einfachen Namen referenziert, nicht über diese ( dies in der inneren Klasse bezieht sich auf die Instanz der inneren Klasse, nicht auf die zugehörige enthaltende Klasseninstanz):
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
In der inneren Klasse können Sie diese der enthaltenden Klasse als Rhino.this bezeichnen , und Sie können dies verwenden , um auf ihre Mitglieder zu verweisen, z . B. Rhino.this.barry .
Eine lokale innere Klasse ist eine Klasse, die im Hauptteil einer Methode deklariert ist. Eine solche Klasse ist nur innerhalb ihrer enthaltenden Methode bekannt, daher kann sie nur instanziiert werden und auf ihre Mitglieder kann innerhalb ihrer enthaltenden Methode zugegriffen werden. Der Vorteil besteht darin, dass eine lokale Instanz der inneren Klasse an die endgültigen lokalen Variablen ihrer enthaltenen Methode gebunden ist und auf diese zugreifen kann. Wenn die Instanz ein endgültiges lokales Element ihrer enthaltenen Methode verwendet, behält die Variable den Wert bei, den sie zum Zeitpunkt der Erstellung der Instanz hatte, auch wenn die Variable den Gültigkeitsbereich verlassen hat (dies ist effektiv Javas grobe, begrenzte Version von Schließungen).
Da eine lokale innere Klasse weder Mitglied einer Klasse noch eines Pakets ist, wird sie nicht mit einer Zugriffsebene deklariert. (Stellen Sie jedoch klar, dass die eigenen Mitglieder Zugriffsebenen wie in einer normalen Klasse haben.)
Wenn eine lokale innere Klasse wird in einer Instanz Methode deklariert, eine Instantiierung der inneren Klasse wird auf die Instanz gebunden durch die enthaltende Methode des gehalten dieser zum Zeitpunkt der Erstellung der Instanz, und so die Instanzmitglieder enthaltenden Klasse zugänglich sind wie in einer Instanz innere Klasse. Eine lokale innere Klasse wird einfach über ihren Namen instanziiert , z. B. wird die lokale innere Klasse Cat als neue Cat () instanziiert , nicht wie erwartet als this.Cat ().
Eine anonyme innere Klasse ist eine syntaktisch bequeme Methode zum Schreiben einer lokalen inneren Klasse. Am häufigsten wird eine lokale innere Klasse höchstens einmal instanziiert, wenn ihre enthaltende Methode ausgeführt wird. Es wäre also schön, wenn wir die lokale innere Klassendefinition und ihre einzelne Instanziierung in einer praktischen Syntaxform kombinieren könnten, und es wäre auch schön, wenn wir uns keinen Namen für die Klasse ausdenken müssten (je weniger nicht hilfreich) Namen, die Ihr Code enthält, desto besser). Eine anonyme innere Klasse erlaubt beides:
new *ParentClassName*(*constructorArgs*) {*members*}
Dies ist ein Ausdruck, der eine neue Instanz einer unbenannten Klasse zurückgibt, die ParentClassName erweitert . Sie können keinen eigenen Konstruktor angeben. Vielmehr wird implizit einer angegeben, der einfach den Superkonstruktor aufruft, sodass die angegebenen Argumente zum Superkonstruktor passen müssen. (Wenn das übergeordnete Element mehrere Konstruktoren enthält, wird der "einfachste" als "einfachster" bezeichnet, was durch ein ziemlich komplexes Regelwerk bestimmt wird, das es nicht wert ist, im Detail gelernt zu werden. Achten Sie nur darauf, was NetBeans oder Eclipse Ihnen sagen.)
Alternativ können Sie eine zu implementierende Schnittstelle angeben:
new *InterfaceName*() {*members*}
Eine solche Deklaration erstellt eine neue Instanz einer unbenannten Klasse, die Object erweitert und InterfaceName implementiert . Auch hier können Sie keinen eigenen Konstruktor angeben. In diesem Fall liefert Java implizit einen Konstruktor ohne Argumente und ohne Handeln (in diesem Fall gibt es also niemals Konstruktorargumente).
Auch wenn Sie einer anonymen inneren Klasse keinen Konstruktor zuweisen können, können Sie dennoch ein beliebiges Setup mit einem Initialisierungsblock (einem {} Block außerhalb einer Methode) durchführen.
Stellen Sie klar, dass eine anonyme innere Klasse einfach eine weniger flexible Möglichkeit ist, eine lokale innere Klasse mit einer Instanz zu erstellen. Wenn Sie eine lokale innere Klasse möchten, die mehrere Schnittstellen implementiert oder Schnittstellen implementiert, während eine andere Klasse als Object erweitert wird, oder die ihren eigenen Konstruktor angibt, müssen Sie keine reguläre benannte lokale innere Klasse erstellen.
Ich glaube nicht, dass der wirkliche Unterschied in den obigen Antworten deutlich wurde.
Zuerst, um die Bedingungen richtig zu machen:
Martins Antwort ist soweit richtig. Die eigentliche Frage lautet jedoch: Was ist der Zweck, eine verschachtelte Klasse als statisch zu deklarieren oder nicht?
Sie verwenden statisch verschachtelte Klassen, wenn Sie Ihre Klassen nur zusammenhalten möchten, wenn sie aktuell zusammengehören oder wenn die verschachtelte Klasse ausschließlich in der umschließenden Klasse verwendet wird. Es gibt keinen semantischen Unterschied zwischen einer statisch verschachtelten Klasse und jeder anderen Klasse.
Nicht statisch verschachtelte Klassen sind ein anderes Tier. Ähnlich wie anonyme innere Klassen sind solche verschachtelten Klassen tatsächlich Schließungen. Das heißt, sie erfassen ihren umgebenden Bereich und ihre umschließende Instanz und machen diese zugänglich. Vielleicht wird ein Beispiel das klarstellen. Sehen Sie diesen Stummel eines Containers:
public class Container {
public class Item{
Object data;
public Container getContainer(){
return Container.this;
}
public Item(Object data) {
super();
this.data = data;
}
}
public static Item create(Object data){
// does not compile since no instance of Container is available
return new Item(data);
}
public Item createSubItem(Object data){
// compiles, since 'this' Container is available
return new Item(data);
}
}
In diesem Fall möchten Sie einen Verweis von einem untergeordneten Element auf den übergeordneten Container haben. Bei Verwendung einer nicht statisch verschachtelten Klasse funktioniert dies ohne Arbeit. Sie können mit der Syntax auf die umschließende Instanz von Container zugreifen Container.this
.
Weitere Hardcore-Erklärungen folgen:
Wenn Sie sich die Java-Bytecodes ansehen, die der Compiler für eine (nicht statische) verschachtelte Klasse generiert, wird dies möglicherweise noch deutlicher:
// class version 49.0 (49)
// access flags 33
public class Container$Item {
// compiled from: Container.java
// access flags 1
public INNERCLASS Container$Item Container Item
// access flags 0
Object data
// access flags 4112
final Container this$0
// access flags 1
public getContainer() : Container
L0
LINENUMBER 7 L0
ALOAD 0: this
GETFIELD Container$Item.this$0 : Container
ARETURN
L1
LOCALVARIABLE this Container$Item L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 1
public <init>(Container,Object) : void
L0
LINENUMBER 12 L0
ALOAD 0: this
ALOAD 1
PUTFIELD Container$Item.this$0 : Container
L1
LINENUMBER 10 L1
ALOAD 0: this
INVOKESPECIAL Object.<init>() : void
L2
LINENUMBER 11 L2
ALOAD 0: this
ALOAD 2: data
PUTFIELD Container$Item.data : Object
RETURN
L3
LOCALVARIABLE this Container$Item L0 L3 0
LOCALVARIABLE data Object L0 L3 2
MAXSTACK = 2
MAXLOCALS = 3
}
Wie Sie sehen, erstellt der Compiler ein verstecktes Feld Container this$0
. Dies wird im Konstruktor festgelegt, der einen zusätzlichen Parameter vom Typ Container hat, um die einschließende Instanz anzugeben. Sie können diesen Parameter nicht in der Quelle sehen, aber der Compiler generiert ihn implizit für eine verschachtelte Klasse.
Martins Beispiel
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
würde also zu einem Aufruf von so etwas wie (in Bytecodes) kompiliert werden
new InnerClass(outerObject)
Der Vollständigkeit halber:
Eine anonyme Klasse ist ein perfektes Beispiel für eine nicht statisch verschachtelte Klasse, der nur kein Name zugeordnet ist und auf die später nicht verwiesen werden kann.
Ich denke, dass keine der obigen Antworten Ihnen den wirklichen Unterschied zwischen einer verschachtelten Klasse und einer statischen verschachtelten Klasse im Hinblick auf das Anwendungsdesign erklärt:
Eine verschachtelte Klasse kann nicht statisch oder statisch sein und ist jeweils eine Klasse, die in einer anderen Klasse definiert ist . Eine verschachtelte Klasse sollte nur existieren, um die einschließende Klasse zu bedienen . Wenn eine verschachtelte Klasse von anderen Klassen (nicht nur der einschließenden) nützlich ist, sollte sie als Klasse der obersten Ebene deklariert werden.
Nicht statische verschachtelte Klasse : Wird implizit der einschließenden Instanz der enthaltenden Klasse zugeordnet. Dies bedeutet, dass Methoden und Zugriffsvariablen der einschließenden Instanz aufgerufen werden können. Eine häufige Verwendung einer nicht statisch verschachtelten Klasse ist das Definieren einer Adapterklasse.
Statische verschachtelte Klasse : Kann nicht auf die Instanz der umschließenden Klasse zugreifen und Methoden darauf aufrufen. Sollte daher verwendet werden, wenn die verschachtelte Klasse keinen Zugriff auf eine Instanz der umschließenden Klasse erfordert. Eine übliche Verwendung einer statisch verschachtelten Klasse besteht darin, Komponenten des äußeren Objekts zu implementieren.
Der Hauptunterschied zwischen den beiden besteht also vom Entwurfsstandpunkt aus: Nicht statisch verschachtelte Klassen können auf Instanzen der Containerklasse zugreifen, statische nicht .
In einfachen Worten, wir brauchen verschachtelte Klassen hauptsächlich, weil Java keine Abschlüsse bietet.
Verschachtelte Klassen sind Klassen, die im Hauptteil einer anderen umschließenden Klasse definiert sind. Es gibt zwei Arten - statische und nicht statische.
Sie werden als Mitglieder der einschließenden Klasse behandelt, daher können Sie einen der vier Zugriffsspezifizierer angeben - private, package, protected, public
. Wir haben diesen Luxus nicht mit erstklassigen Klassen, die nur deklariert public
oder paketprivat sein können.
Innere Klassen, auch Nicht-Stack-Klassen genannt, haben Zugriff auf andere Mitglieder der Top-Klasse, auch wenn sie als privat deklariert sind, während statisch verschachtelte Klassen keinen Zugriff auf andere Mitglieder der Top-Klasse haben.
public class OuterClass {
public static class Inner1 {
}
public class Inner2 {
}
}
Inner1
ist unsere statische innere Klasse und Inner2
ist unsere innere Klasse, die nicht statisch ist. Der Hauptunterschied zwischen ihnen besteht darin, dass Sie keine Inner2
Instanz ohne Outer erstellen können, da Sie ein Inner1
Objekt unabhängig erstellen können.
Wann würden Sie die innere Klasse verwenden?
Stellen Sie sich eine Situation vor, in der Class A
und Class B
in Beziehung stehen, Class B
auf Class A
Mitglieder zugegriffen werden muss und Class B
nur in Beziehung steht Class A
. Innere Klassen kommen ins Spiel.
Um eine Instanz der inneren Klasse zu erstellen, müssen Sie eine Instanz Ihrer äußeren Klasse erstellen.
OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();
oder
OuterClass.Inner2 inner = new OuterClass().new Inner2();
Wann würden Sie die statische innere Klasse verwenden?
Sie würden eine statische innere Klasse definieren, wenn Sie wissen, dass sie keine Beziehung zur Instanz der einschließenden Klasse / Top-Klasse hat. Wenn Ihre innere Klasse keine Methoden oder Felder der äußeren Klasse verwendet, ist dies nur Platzverschwendung. Machen Sie sie also statisch.
Verwenden Sie beispielsweise diese Syntax, um ein Objekt für die statisch verschachtelte Klasse zu erstellen:
OuterClass.Inner1 nestedObject = new OuterClass.Inner1();
Der Vorteil einer statisch verschachtelten Klasse besteht darin, dass sie kein Objekt der enthaltenden Klasse / Top-Klasse benötigt, um zu funktionieren. Auf diese Weise können Sie die Anzahl der Objekte reduzieren, die Ihre Anwendung zur Laufzeit erstellt.
OuterClass.Inner2 inner = outer.new Inner2();
?
static inner
ist ein Widerspruch in Begriffen.
Hier finden Sie wichtige Unterschiede und Ähnlichkeiten zwischen der inneren Java-Klasse und der statisch verschachtelten Klasse.
Ich hoffe es hilft!
Wird der Instanz der einschließenden Klasse zugeordnet, um sie zu instanziieren, ist zunächst eine Instanz der äußeren Klasse erforderlich (beachten Sie den neuen Schlüsselwortplatz):
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
Es können keine statischen Elemente selbst definiert werden
Auf Instanzmethoden oder Felder der äußeren Klasse kann nicht zugegriffen werden
Nicht mit einer Instanz der einschließenden Klasse verknüpft. So instanziieren Sie sie:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Laut Oracle-Dokumentation gibt es mehrere Gründe ( vollständige Dokumentation ):
Es ist eine Möglichkeit, Klassen, die nur an einer Stelle verwendet werden, logisch zu gruppieren: Wenn eine Klasse nur für eine andere Klasse nützlich ist, ist es logisch, sie in diese Klasse einzubetten und die beiden zusammenzuhalten. Durch das Verschachteln solcher "Hilfsklassen" wird das Paket optimiert.
Es erhöht die Kapselung: Betrachten Sie zwei Klassen der obersten Ebene, A und B, wobei B Zugriff auf Mitglieder von A benötigt, die andernfalls als privat deklariert würden. Durch das Ausblenden von Klasse B in Klasse A können die Mitglieder von A als privat deklariert werden und B kann auf sie zugreifen. Außerdem kann B selbst vor der Außenwelt verborgen sein.
Dies kann zu besser lesbarem und wartbarem Code führen: Durch das Verschachteln kleiner Klassen in Klassen der obersten Ebene wird der Code näher an dem Ort platziert, an dem er verwendet wird.
Ich denke, die Konvention, die allgemein befolgt wird, ist folgende:
Einige andere Punkte, an die man sich erinnern sollte, sind:
Klassen der obersten Ebene und statisch verschachtelte Klassen sind semantisch identisch, außer dass sie im Fall einer statisch verschachtelten Klasse statisch auf private statische Felder / Methoden ihrer äußeren [übergeordneten] Klasse verweisen können und umgekehrt.
Innere Klassen haben Zugriff auf Instanzvariablen der einschließenden Instanz der Klasse Outer [parent]. Allerdings haben nicht alle inneren Klassen einschließende Instanzen, z. B. innere Klassen in statischen Kontexten, wie eine anonyme Klasse, die in einem statischen Initialisierungsblock verwendet wird.
Die anonyme Klasse erweitert standardmäßig die übergeordnete Klasse oder implementiert die übergeordnete Schnittstelle, und es gibt keine weitere Klausel, um eine andere Klasse zu erweitern oder weitere Schnittstellen zu implementieren. Damit,
new YourClass(){};
meint class [Anonymous] extends YourClass {}
new YourInterface(){};
meint class [Anonymous] implements YourInterface {}
Ich habe das Gefühl, dass die größere Frage, die offen bleibt, welche wann verwendet werden soll? Nun, das hängt hauptsächlich davon ab, mit welchem Szenario Sie es zu tun haben, aber das Lesen der Antwort von @jrudolph kann Ihnen helfen, eine Entscheidung zu treffen.
Verschachtelte Klasse: Klasse innerhalb der Klasse
Typen:
Unterschied:
Nicht statische verschachtelte Klasse [Innere Klasse]
In einer nicht statischen verschachtelten Klasse existieren Objekte der inneren Klasse innerhalb des Objekts der äußeren Klasse. Damit das Datenelement der äußeren Klasse für die innere Klasse zugänglich ist. Um also ein Objekt der inneren Klasse zu erstellen, müssen wir zuerst ein Objekt der äußeren Klasse erstellen.
outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass();
Statisch verschachtelte Klasse
In statischen verschachtelten Klassenobjekten der inneren Klasse wird kein Objekt der äußeren Klasse benötigt, da das Wort "statisch" anzeigt, dass kein Objekt erstellt werden muss.
class outerclass A {
static class nestedclass B {
static int x = 10;
}
}
Wenn Sie auf x zugreifen möchten, schreiben Sie die folgende Inside-Methode
outerclass.nestedclass.x; i.e. System.out.prinltn( outerclass.nestedclass.x);
Die Instanz der inneren Klasse wird erstellt, wenn eine Instanz der äußeren Klasse erstellt wird. Daher haben die Mitglieder und Methoden der inneren Klasse Zugriff auf die Mitglieder und Methoden der Instanz (des Objekts) der äußeren Klasse. Wenn die Instanz der äußeren Klasse den Gültigkeitsbereich verlässt, existieren auch die Instanzen der inneren Klasse nicht mehr.
Die statisch verschachtelte Klasse hat keine konkrete Instanz. Es wird nur geladen, wenn es zum ersten Mal verwendet wird (genau wie die statischen Methoden). Es ist eine völlig unabhängige Entität, deren Methoden und Variablen keinen Zugriff auf die Instanzen der äußeren Klasse haben.
Die statisch verschachtelten Klassen sind nicht mit dem äußeren Objekt gekoppelt, sie sind schneller und sie benötigen keinen Heap- / Stack-Speicher, da keine Instanz einer solchen Klasse erstellt werden muss. Als Faustregel gilt daher, dass versucht wird, eine statisch verschachtelte Klasse mit möglichst begrenztem Umfang zu definieren (privat> = Klasse> = geschützt> = öffentlich) und diese dann in eine innere Klasse zu konvertieren (durch Entfernen des "statischen" Bezeichners) und zu lösen den Umfang, wenn es wirklich notwendig ist.
Die Verwendung verschachtelter statischer Klassen ist subtil und kann in bestimmten Situationen hilfreich sein.
Während statische Attribute instanziiert werden, bevor die Klasse über ihren Konstruktor instanziiert wird, scheinen statische Attribute innerhalb verschachtelter statischer Klassen erst instanziiert zu werden, nachdem der Konstruktor der Klasse aufgerufen wurde, oder zumindest erst, nachdem die Attribute zum ersten Mal referenziert wurden, selbst wenn Sie sind als "endgültig" gekennzeichnet.
Betrachten Sie dieses Beispiel:
public class C0 {
static C0 instance = null;
// Uncomment the following line and a null pointer exception will be
// generated before anything gets printed.
//public static final String outerItem = instance.makeString(98.6);
public C0() {
instance = this;
}
public String makeString(int i) {
return ((new Integer(i)).toString());
}
public String makeString(double d) {
return ((new Double(d)).toString());
}
public static final class nested {
public static final String innerItem = instance.makeString(42);
}
static public void main(String[] argv) {
System.out.println("start");
// Comment out this line and a null pointer exception will be
// generated after "start" prints and before the following
// try/catch block even gets entered.
new C0();
try {
System.out.println("retrieve item: " + nested.innerItem);
}
catch (Exception e) {
System.out.println("failed to retrieve item: " + e.toString());
}
System.out.println("finish");
}
}
Obwohl 'nested' und 'innerItem' beide als 'static final' deklariert sind. Die Einstellung von nested.innerItem erfolgt erst, nachdem die Klasse instanziiert wurde (oder zumindest erst, nachdem das verschachtelte statische Element zum ersten Mal referenziert wurde), wie Sie selbst sehen können, indem Sie die Zeilen, auf die ich verweise, kommentieren und auskommentieren. über. Gleiches gilt nicht für 'OuterItem'.
Zumindest sehe ich das in Java 6.0.
Die Begriffe werden synonym verwendet. Wenn Sie wirklich pedantisch darüber sein wollen, dann sind Sie könnten „verschachtelte Klasse“ definieren , um eine statische innere Klasse zu beziehen, eine , die keine umschließenden Instanz hat. Im Code haben Sie möglicherweise Folgendes:
public class Outer {
public class Inner {}
public static class Nested {}
}
Das ist jedoch keine allgemein akzeptierte Definition.
Beim Erstellen einer Instanz wird die Instanz einer nicht statischen inneren Klasse mit der Referenz des Objekts der äußeren Klasse erstellt, in dem sie definiert ist. Dies bedeutet, dass es eine einschließende Instanz hat. Die Instanz der statischen inneren Klasse wird jedoch mit der Referenz der äußeren Klasse erstellt, nicht mit der Referenz des Objekts der äußeren Klasse. Dies bedeutet, dass es keine Instanz enthält.
Zum Beispiel:
class A
{
class B
{
// static int x; not allowed here…..
}
static class C
{
static int x; // allowed here
}
}
class Test
{
public static void main(String… str)
{
A o=new A();
A.B obj1 =o.new B();//need of inclosing instance
A.C obj2 =new A.C();
// not need of reference of object of outer class….
}
}
Ich denke, hier gibt es nicht viel hinzuzufügen, die meisten Antworten erklären perfekt die Unterschiede zwischen statisch verschachtelten Klassen und inneren Klassen. Beachten Sie jedoch das folgende Problem, wenn Sie verschachtelte Klassen im Vergleich zu inneren Klassen verwenden. Wie erwähnt in ein paar Antworten innere Klassen können nicht ohne und Instanz ihrer umschließenden Klasse instanziiert werden , was bedeutet , dass sie HOLD einen Zeiger auf die Instanz der umgebenden Klasse , die zu einem Speicherüberlauf oder Stapelüberlaufausnahme aufgrund der Tatsache , die GC führen kann wird nicht in der Lage sein, die umschließenden Klassen mit Müll zu sammeln, selbst wenn sie nicht mehr verwendet werden. Um dies zu verdeutlichen, überprüfen Sie den folgenden Code:
public class Outer {
public class Inner {
}
public Inner inner(){
return new Inner();
}
@Override
protected void finalize() throws Throwable {
// as you know finalize is called by the garbage collector due to destroying an object instance
System.out.println("I am destroyed !");
}
}
public static void main(String arg[]) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
// out instance is no more used and should be garbage collected !!!
// However this will not happen as inner instance is still alive i.e used, not null !
// and outer will be kept in memory until inner is destroyed
outer = null;
//
// inner = null;
//kick out garbage collector
System.gc();
}
Wenn Sie den Kommentar zu entfernen, wird das // inner = null;
Programm " Ich bin zerstört! " Ausgeben, aber wenn Sie diesen Kommentar beibehalten, wird dies nicht der Fall sein.
Der Grund dafür ist, dass auf die weiße innere Instanz immer noch verwiesen wird. GC kann sie nicht erfassen, und da sie auf die äußere Instanz verweist (einen Zeiger darauf hat), wird sie auch nicht erfasst. Sie haben genug von diesen Objekten in Ihrem Projekt und es kann nicht mehr genügend Speicher vorhanden sein.
Im Vergleich zu statischen inneren Klassen, die keinen Punkt zur inneren Klasseninstanz enthalten, da sie nicht instanzbezogen, sondern klassenbezogen sind. Das obige Programm kann " Ich bin zerstört! " Drucken, wenn Sie die innere Klasse statisch machen und mit instanziierenOuter.Inner i = new Outer.Inner();
Verschachtelte Klasse ist ein sehr allgemeiner Begriff: Jede Klasse, die nicht der obersten Ebene entspricht, ist eine verschachtelte Klasse. Eine innere Klasse ist eine nicht statisch verschachtelte Klasse. Joseph Darcy schrieb eine sehr schöne Erklärung über verschachtelte, innere, Mitglieder- und Top-Level-Klassen .
Ähm ... eine innere Klasse IST eine verschachtelte Klasse ... meinst du anonyme Klasse und innere Klasse?
Bearbeiten: Wenn Sie tatsächlich inner oder anonym gemeint haben ... ist eine innere Klasse nur eine Klasse, die innerhalb einer Klasse definiert ist, wie z.
public class A {
public class B {
}
}
Während eine anonyme Klasse eine Erweiterung einer anonym definierten Klasse ist, wird keine tatsächliche "Klasse definiert, wie in:
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
Weitere Bearbeitung:
Wikipedia behauptet, dass es einen Unterschied in Java gibt, aber ich arbeite seit 8 Jahren mit Java und es ist das erste Mal, dass ich eine solche Unterscheidung höre ... ganz zu schweigen davon, dass es dort keine Referenzen gibt, die die Behauptung stützen ... unten Zeile, eine innere Klasse ist eine Klasse, die innerhalb einer Klasse definiert ist (statisch oder nicht), und verschachtelt ist nur ein anderer Begriff, der dasselbe bedeutet.
Es gibt einen subtilen Unterschied zwischen statischer und nicht statischer verschachtelter Klasse ... Grundsätzlich haben nicht statische innere Klassen impliziten Zugriff auf Instanzfelder und Methoden der einschließenden Klasse (daher können sie nicht in einem statischen Kontext erstellt werden, sondern sind ein Compiler Error). Statisch verschachtelte Klassen haben dagegen keinen impliziten Zugriff auf Instanzfelder und -methoden und können in einem statischen Kontext erstellt werden.
Zielgruppe sind Lernende, die noch keine Erfahrung mit Java und / oder verschachtelten Klassen haben
Verschachtelte Klassen können entweder:
1. Statisch verschachtelte Klassen sein.
2. Nicht statisch verschachtelte Klassen. (auch als innere Klassen bekannt ) => Bitte denken Sie daran
1.Inner Klassen
Beispiel:
class OuterClass {
/* some code here...*/
class InnerClass { }
/* some code here...*/
}
Innere Klassen sind Teilmengen verschachtelter Klassen:
Spezialität der inneren Klasse:
2.Statische verschachtelte Klassen:
Beispiel:
class EnclosingClass {
static class Nested {
void someMethod() { System.out.println("hello SO"); }
}
}
Fall 1: Instanziieren einer statisch verschachtelten Klasse aus einer nicht einschließenden Klasse
class NonEnclosingClass {
public static void main(String[] args) {
/*instantiate the Nested class that is a static
member of the EnclosingClass class:
*/
EnclosingClass.Nested n = new EnclosingClass.Nested();
n.someMethod(); //prints out "hello"
}
}
Fall 2: Instanziieren einer statisch verschachtelten Klasse aus einer umschließenden Klasse
class EnclosingClass {
static class Nested {
void anotherMethod() { System.out.println("hi again"); }
}
public static void main(String[] args) {
//access enclosed class:
Nested n = new Nested();
n.anotherMethod(); //prints out "hi again"
}
}
Spezialität der statischen Klassen:
Schlussfolgerung:
Frage: Was ist der Hauptunterschied zwischen einer inneren Klasse und einer statisch verschachtelten Klasse in Java?
Antwort: Gehen Sie einfach die Einzelheiten der oben genannten Klassen durch.
Die innere Klasse und die verschachtelte statische Klasse in Java sind Klassen, die in einer anderen Klasse deklariert sind, die in Java als Top-Level-Klasse bezeichnet wird. Wenn Sie in der Java-Terminologie eine verschachtelte Klasse als statisch deklarieren, wird sie in Java als verschachtelte statische Klasse bezeichnet, während nicht statische verschachtelte Klassen einfach als innere Klasse bezeichnet werden.
Was ist die innere Klasse in Java?
Jede Klasse, die keine oberste Ebene ist oder in einer anderen Klasse deklariert ist, wird als verschachtelte Klasse bezeichnet. Von diesen verschachtelten Klassen werden Klassen, die als nicht statisch deklariert sind, in Java als innere Klasse bezeichnet. In Java gibt es drei Arten von inneren Klassen:
1) Lokale innere Klasse - wird in einem Codeblock oder einer Methode deklariert.
2) Anonyme innere Klasse - ist eine Klasse, deren Name nicht referenziert und an derselben Stelle initialisiert werden soll, an der sie erstellt wird.
3) Mitglied innere Klasse - wird als nicht statisches Mitglied der äußeren Klasse deklariert.
public class InnerClassTest {
public static void main(String args[]) {
//creating local inner class inside method i.e. main()
class Local {
public void name() {
System.out.println("Example of Local class in Java");
}
}
//creating instance of local inner class
Local local = new Local();
local.name(); //calling method from local inner class
//Creating anonymous inner class in Java for implementing thread
Thread anonymous = new Thread(){
@Override
public void run(){
System.out.println("Anonymous class example in java");
}
};
anonymous.start();
//example of creating instance of inner class
InnerClassTest test = new InnerClassTest();
InnerClassTest.Inner inner = test.new Inner();
inner.name(); //calling method of inner class
}
//Creating Inner class in Java
private class Inner{
public void name(){
System.out.println("Inner class example in java");
}
}
}
Was ist eine verschachtelte statische Klasse in Java?
Verschachtelte statische Klasse ist eine andere Klasse, die innerhalb einer Klasse als Mitglied deklariert und statisch gemacht wird. Verschachtelte statische Klasse wird auch als Mitglied der äußeren Klasse deklariert und kann wie jedes andere Mitglied privat, öffentlich oder geschützt werden. Einer der Hauptvorteile der verschachtelten statischen Klasse gegenüber der inneren Klasse besteht darin, dass die Instanz der verschachtelten statischen Klasse keiner umschließenden Instanz der äußeren Klasse zugeordnet ist. Sie benötigen auch keine Instanz der äußeren Klasse, um eine Instanz der verschachtelten statischen Klasse in Java zu erstellen .
1) Es kann auf statische Datenelemente der äußeren Klasse einschließlich privater Daten zugreifen .
2) Eine statisch verschachtelte Klasse kann nicht auf nicht statische (Instanz-) Datenelemente oder Methoden zugreifen .
public class NestedStaticExample {
public static void main(String args[]){
StaticNested nested = new StaticNested();
nested.name();
}
//static nested class in java
private static class StaticNested{
public void name(){
System.out.println("static nested class example in java");
}
}
}
Ref: Innere Klasse und verschachtelte statische Klasse in Java mit Beispiel
Ich denke, die Leute hier sollten Poster bemerken, dass: Statische Nestklasse nur die erste innere Klasse ist. Zum Beispiel:
public static class A {} //ERROR
public class A {
public class B {
public static class C {} //ERROR
}
}
public class A {
public static class B {} //COMPILE !!!
}
Zusammenfassend hängt die statische Klasse also nicht davon ab, welche Klasse sie enthält. Sie können also nicht in der normalen Klasse sein. (weil normale Klasse eine Instanz benötigt).
Wenn wir eine statische Elementklasse innerhalb einer Klasse deklarieren, wird sie als verschachtelte Klasse der obersten Ebene oder als statische verschachtelte Klasse bezeichnet. Es kann wie folgt demonstriert werden:
class Test{
private static int x = 1;
static class A{
private static int y = 2;
public static int getZ(){
return B.z+x;
}
}
static class B{
private static int z = 3;
public static int getY(){
return A.y;
}
}
}
class TestDemo{
public static void main(String[] args){
Test t = new Test();
System.out.println(Test.A.getZ());
System.out.println(Test.B.getY());
}
}
Wenn wir eine nicht statische Elementklasse innerhalb einer Klasse deklarieren, wird dies als innere Klasse bezeichnet. Die innere Klasse kann wie folgt demonstriert werden:
class Test{
private int i = 10;
class A{
private int i =20;
void display(){
int i = 30;
System.out.println(i);
System.out.println(this.i);
System.out.println(Test.this.i);
}
}
}
Das Folgende ist ein Beispiel für static nested class
und inner class
:
OuterClass.java
public class OuterClass {
private String someVariable = "Non Static";
private static String anotherStaticVariable = "Static";
OuterClass(){
}
//Nested classes are static
static class StaticNestedClass{
private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable";
//can access private variables declared in the outer class
public static void getPrivateVariableofOuterClass(){
System.out.println(anotherStaticVariable);
}
}
//non static
class InnerClass{
//can access private variables of outer class
public String getPrivateNonStaticVariableOfOuterClass(){
return someVariable;
}
}
public static void accessStaticClass(){
//can access any variable declared inside the Static Nested Class
//even if it private
String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable;
System.out.println(var);
}
}
OuterClassTest:
public class OuterClassTest {
public static void main(String[] args) {
//access the Static Nested Class
OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();
//test the private variable declared inside the static nested class
OuterClass.accessStaticClass();
/*
* Inner Class Test
* */
//Declaration
//first instantiate the outer class
OuterClass outerClass = new OuterClass();
//then instantiate the inner class
OuterClass.InnerClass innerClassExample = outerClass. new InnerClass();
//test the non static private variable
System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass());
}
}
Ich denke, dass keine der obigen Antworten Ihnen das wirkliche Beispiel für den Unterschied zwischen einer verschachtelten Klasse und einer statischen verschachtelten Klasse in Bezug auf das Anwendungsdesign gibt. Der Hauptunterschied zwischen statisch verschachtelter Klasse und innerer Klasse besteht in der Möglichkeit, auf das Instanzfeld der äußeren Klasse zuzugreifen.
Schauen wir uns die beiden folgenden Beispiele an.
Statische Verschachtelungsklasse: Ein gutes Beispiel für die Verwendung statisch verschachtelter Klassen ist das Builder-Muster ( https://dzone.com/articles/design-patterns-the-builder-pattern ).
Für BankAccount verwenden wir eine statisch verschachtelte Klasse, hauptsächlich weil
Eine statische Nestklasseninstanz kann vor der äußeren Klasse erstellt werden.
Im Builder-Muster ist der Builder eine Hilfsklasse, mit der das Bankkonto erstellt wird.
public class BankAccount {
private long accountNumber;
private String owner;
...
public static class Builder {
private long accountNumber;
private String owner;
...
static public Builder(long accountNumber) {
this.accountNumber = accountNumber;
}
public Builder withOwner(String owner){
this.owner = owner;
return this;
}
...
public BankAccount build(){
BankAccount account = new BankAccount();
account.accountNumber = this.accountNumber;
account.owner = this.owner;
...
return account;
}
}
}
Innere Klasse: Eine häufige Verwendung innerer Klassen ist das Definieren eines Ereignishandlers. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html
Für MyClass verwenden wir die innere Klasse, hauptsächlich weil:
Innere Klasse MyAdapter muss auf das äußere Klassenmitglied zugreifen.
In diesem Beispiel ist MyAdapter nur MyClass zugeordnet. Keine anderen Klassen beziehen sich auf MyAdapter. Daher ist es besser, sie zusammen zu organisieren, ohne eine Namenskonvention zu verwenden
public class MyClass extends Applet {
...
someObject.addMouseListener(new MyAdapter());
...
class MyAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
...// Event listener implementation goes here...
...// change some outer class instance property depend on the event
}
}
}
Erstens gibt es keine solche Klasse, die als statische Klasse bezeichnet wird. Der statische Modifikator, der mit der inneren Klasse (als verschachtelte Klasse bezeichnet) verwendet wird, besagt, dass es sich um ein statisches Mitglied der äußeren Klasse handelt, was bedeutet, dass wir wie bei anderen statischen Elementen und ohne solche darauf zugreifen können Instanz der äußeren Klasse. (Was ursprünglich von statischen Vorteilen profitiert.)
Der Unterschied zwischen der Verwendung der verschachtelten Klasse und der regulären inneren Klasse ist:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
Zuerst können wir die äußere Klasse instanziieren, dann können wir auf die innere Klasse zugreifen.
Wenn Class jedoch verschachtelt ist, lautet die Syntax:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
Womit die statische Syntax als normale Implementierung des statischen Schlüsselworts verwendet wird.
Mit der Programmiersprache Java können Sie eine Klasse innerhalb einer anderen Klasse definieren. Eine solche Klasse wird als verschachtelte Klasse bezeichnet und hier dargestellt:
class OuterClass {
...
class NestedClass {
...
}
}
Verschachtelte Klassen werden in zwei Kategorien unterteilt: statisch und nicht statisch. Verschachtelte Klassen, die als statisch deklariert sind, werden als statisch verschachtelte Klassen bezeichnet. Nicht statische verschachtelte Klassen werden als innere Klassen bezeichnet. Eine Sache, die wir beachten sollten, ist, dass nicht statisch verschachtelte Klassen (innere Klassen) Zugriff auf andere Mitglieder der einschließenden Klasse haben, selbst wenn sie als privat deklariert sind. Statisch verschachtelte Klassen haben nur dann Zugriff auf andere Mitglieder der einschließenden Klasse, wenn diese statisch sind. Es kann nicht auf nicht statische Mitglieder der äußeren Klasse zugreifen. Wie bei Klassenmethoden und -variablen ist eine statische verschachtelte Klasse ihrer äußeren Klasse zugeordnet. Verwenden Sie beispielsweise diese Syntax, um ein Objekt für die statisch verschachtelte Klasse zu erstellen:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
Um eine innere Klasse zu instanziieren, müssen Sie zuerst die äußere Klasse instanziieren. Erstellen Sie dann das innere Objekt innerhalb des äußeren Objekts mit folgender Syntax:
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
Warum wir verschachtelte Klassen verwenden
Der Unterschied besteht darin, dass eine verschachtelte Klassendeklaration, die ebenfalls statisch ist, außerhalb der einschließenden Klasse instanziiert werden kann.
Wenn Sie eine verschachtelte Klassendeklaration haben, die nicht statisch ist und auch als innere Klasse bezeichnet wird, können Sie sie in Java nur über die einschließende Klasse instanziieren. Das aus der inneren Klasse erstellte Objekt ist mit dem aus der äußeren Klasse erstellten Objekt verknüpft, sodass die innere Klasse auf die Felder der äußeren Klasse verweisen kann.
Wenn es jedoch statisch ist, existiert der Link nicht, auf die äußeren Felder kann nicht zugegriffen werden (außer über eine normale Referenz wie bei jedem anderen Objekt), und Sie können daher die verschachtelte Klasse selbst instanziieren.
Es ist ziemlich einfach, statische lokale Klassen und nicht statische innere Klassen zu vergleichen.
Unterschiede:
Statische lokale Klasse:
Kann nur auf statische Mitglieder der äußeren Klasse zugreifen.
Kann keine statischen Initialisierer haben
Kann nicht direkt von außerhalb der Funktion aufgerufen werden, in der sie deklariert ist
Ich habe verschiedene mögliche Fehler- und Fehlerszenarien dargestellt, die im Java-Code auftreten können.
class Outter1 {
String OutStr;
Outter1(String str) {
OutStr = str;
}
public void NonStaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// below static attribute not permitted
// static String tempStatic1 = "static";
// below static with final attribute not permitted
// static final String tempStatic1 = "ashish";
// synchronized keyword is not permitted below
class localInnerNonStatic1 {
synchronized public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
public static void StaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// static attribute not permitted below
//static String tempStatic1 = "static";
// static with final attribute not permitted below
// static final String tempStatic1 = "ashish";
class localInnerNonStatic1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
// synchronized keyword is not permitted
static class inner1 {
static String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
public static void innerStaticMethod(String str11) {
// error in below step
str11 = temp1 +" india";
//str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
//}
}
//synchronized keyword is not permitted below
class innerNonStatic1 {
//This is important we have to keep final with static modifier in non
// static innerclass below
static final String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
synchronized public void innerMethod(String str11) {
tempNonStatic = tempNonStatic +" ...";
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// error in below step
public static void innerStaticMethod(String str11) {
// error in below step
// str11 = tempNonStatic +" india";
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
//}
}
}
item 22 : Favor static member classes over non static