Java innere Klasse und statische verschachtelte Klasse


1766

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?


65
Joshua Blochs Antwort ist in Effective Java gelesen item 22 : Favor static member classes over non static
Raymond Chenon

4
Für die Aufzeichnung ist es Punkt 24 in der 3. Ausgabe des gleichen Buches.
ZeroCool

Antworten:


1696

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.


130
Beachten Sie, dass Sie eine statisch verschachtelte Klasse auch direkt importieren können, dh (oben in der Datei): import OuterClass.StaticNestedClass; Verweisen Sie dann auf die Klasse genauso wie auf OuterClass.
Camilo Díaz Repka

4
@Martin Gibt es einen bestimmten technischen Namen für diese Redewendung, eine innere Klasse zu schaffen OuterClass.InnerClass innerObject = outerObject.new InnerClass();?
Geek

7
Was ist also die Verwendung einer privaten statischen verschachtelten Klasse? Ich denke, wir können es nicht von außen instanziieren wie OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass ();
RoboAlex

1
@Ilya Kogan: Ich meinte, dass ich weiß, dass wir auf statische oder nicht statische Klassenfelder der Eltern zugreifen können (wenn die untergeordnete Klasse eine nicht statische Klasse ist). Ich habe ihre Funktionen einige Male verwendet, aber ich habe mich gefragt, welche Art von Speichermodell Sie folgen? Werden sie von OOP-Konzepten als separates Konzept behandelt? wenn nicht, wo sie wirklich in OOP passen. Scheint mir wie eine Freundesklasse :)
Mubashar

4
@martin, ich weiß, dass ich unglaublich spät zu diesem Thread komme, aber: Es ist Ihre Variable, a, die ein statisches Feld der Klasse A ist. Das bedeutet nicht, dass die anonyme Klasse von 'new A () {int t erstellt wurde () {return 2; }} 'ist genauso statisch, als wenn ich dem statischen Feld a einfach ein anderes Objekt zugewiesen hätte, a, wie in: Klasse B {statische Leere main (Zeichenfolge s) {Aa = new A ()}} (A & B in derselben Paket) Dies macht A nicht zu einer statischen Klasse. Der Ausdruck "statischer Kontext" in der Referenz, die in dem von Ihnen verlinkten Thread zitiert wird, ist unglaublich vage. Tatsächlich wurde dies in vielen Kommentaren in diesem Thread erwähnt.
GrantRobertson

599

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:

  • Organisation: Manchmal erscheint es am sinnvollsten, eine Klasse in den Namespace einer anderen Klasse zu sortieren, insbesondere wenn sie in keinem anderen Kontext verwendet wird
  • Zugriff: Verschachtelte Klassen haben speziellen Zugriff auf die Variablen / Felder ihrer enthaltenen Klassen (genau welche Variablen / Felder von der Art der verschachtelten Klasse abhängen, ob innerlich oder statisch).
  • Bequemlichkeit: Das Erstellen einer neuen Datei für jeden neuen Typ ist wiederum lästig, insbesondere wenn der Typ nur in einem Kontext verwendet wird

In Java gibt es vier Arten verschachtelter Klassen . Kurz gesagt, sie sind:

  • statische Klasse : Als statisches Mitglied einer anderen Klasse deklariert
  • innere Klasse : als Instanzmitglied einer anderen Klasse deklariert
  • lokale innere Klasse : deklariert innerhalb einer Instanzmethode einer anderen Klasse
  • anonyme innere Klasse : wie eine lokale innere Klasse, jedoch als Ausdruck geschrieben, der ein einmaliges Objekt zurückgibt

Lassen Sie mich näher darauf eingehen.


Statische Klassen

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.


Innere Klassen

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 .


Lokale innere Klassen

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 ().


Anonyme innere Klassen

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.


39
Tolle Geschichte, danke. Es hat jedoch einen Fehler. Sie können von Rhino.this.variableName aus von einer inneren Instanzklasse auf die Felder einer äußeren Klasse zugreifen.
Thirler

2
Während Sie keinen eigenen Konstruktor für anonyme innere Klassen bereitstellen können, können Sie die Initialisierung mit doppelter Klammer verwenden. c2.com/cgi/wiki?DoubleBraceInitialization
Casebash

30
Tolle Erklärung, aber ich bin nicht damit einverstanden, dass statische innere Klassen wertlos sind. Unter rwhansen.blogspot.com/2007/07/… finden Sie eine große Variation des Builder-Musters, die stark von der Verwendung statischer innerer Klassen abhängt.
Mansoor Siddiqui

9
Ich bin auch anderer Meinung, dass statische innere Klasse wertlos ist: Wenn Sie eine Aufzählung in der inneren Klasse wollen, müssen Sie die innere Klasse statisch machen.
Jemand irgendwo

9
Private statische verschachtelte Klassen sind ebenfalls sehr nützlich: Sie möchten sie haben, aber Sie möchten sie nicht verfügbar machen. Wie Eintrag <T> in einer LinkedList <T> oder AsyncTasks in einer Aktivität (Android) usw.
Lorenzo Dematté

150

Ich glaube nicht, dass der wirkliche Unterschied in den obigen Antworten deutlich wurde.

Zuerst, um die Bedingungen richtig zu machen:

  • Eine verschachtelte Klasse ist eine Klasse, die auf Quellcodeebene in einer anderen Klasse enthalten ist.
  • Es ist statisch, wenn Sie es mit dem statischen Modifikator deklarieren .
  • Eine nicht statisch verschachtelte Klasse wird als innere Klasse bezeichnet. (Ich bleibe bei einer nicht statisch verschachtelten Klasse.)

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.


17
"Es gibt keinen semantischen Unterschied zwischen einer statisch verschachtelten Klasse und jeder anderen Klasse." Außer dass die verschachtelte Klasse die privaten Felder / Methoden des übergeordneten Elements und die übergeordnete Klasse die privaten Felder / Methoden des verschachtelten Elements sehen kann.
Brad Cupit

Würde die nicht statische innere Klasse nicht möglicherweise massive Speicherlecks verursachen? Wie in, jedes Mal, wenn Sie einen Listener erstellen, erstellen Sie ein Leck?
G_V

3
@G_V Es besteht definitiv die Möglichkeit von Speicherlecks, da eine Instanz der inneren Klasse einen Verweis auf die äußere Klasse enthält. Ob dies ein tatsächliches Problem ist, hängt davon ab, wo und wie Verweise auf Instanzen der äußeren und der inneren Klasse gehalten werden.
Jrudolph

94

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:

Überblick

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.

Unterschied

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.

Fazit

Der Hauptunterschied zwischen den beiden besteht also vom Entwurfsstandpunkt aus: Nicht statisch verschachtelte Klassen können auf Instanzen der Containerklasse zugreifen, statische nicht .


: aus Ihrer Schlussfolgerung "während statisch nicht kann", nicht einmal statische Instanzen des Containers? Sicher?
VdeX

Eine häufig verwendete statisch verschachtelte Klasse ist das ViewHolder-Entwurfsmuster in RecyclerView und ListView.
Hamzeh Soboh

1
In vielen Fällen ist die kurze Antwort klarer und besser. Dies ist ein solches Beispiel.
Eric Wang

32

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 publicoder 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 {
    }
}

Inner1ist unsere statische innere Klasse und Inner2ist unsere innere Klasse, die nicht statisch ist. Der Hauptunterschied zwischen ihnen besteht darin, dass Sie keine Inner2Instanz ohne Outer erstellen können, da Sie ein Inner1Objekt unabhängig erstellen können.

Wann würden Sie die innere Klasse verwenden?

Stellen Sie sich eine Situation vor, in der Class Aund Class Bin Beziehung stehen, Class Bauf Class AMitglieder zugegriffen werden muss und Class Bnur 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.


3
meinst du OuterClass.Inner2 inner = outer.new Inner2();?
Erik Kaplun

4
static innerist ein Widerspruch in Begriffen.
Marquis von Lorne

Und innere Klassen werden nicht auch als "Nicht-Stapel-Klassen" bezeichnet. Verwenden Sie die Code-Formatierung nicht für Text, der kein Code ist, und verwenden Sie sie für Text, der kein Code ist.
Marquis von Lorne

30

Hier finden Sie wichtige Unterschiede und Ähnlichkeiten zwischen der inneren Java-Klasse und der statisch verschachtelten Klasse.

Ich hoffe es hilft!

Innere Klasse

  • Kann sowohl auf instanzielle als auch auf statische Methoden und Felder auf die äußere Klasse zugreifen
  • 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

  • Kann nicht haben Klasse oder Schnittstelle Erklärung

Statisch verschachtelte Klasse

  • 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();

Ähnlichkeiten

  • Beide inneren Klassen können sogar auf private Felder und Methoden der äußeren Klasse zugreifen
  • Auch die Außen Klasse Zugriff haben private Felder und Methoden der inneren Klassen
  • Beide Klassen können einen privaten, geschützten oder öffentlichen Zugriffsmodifikator haben

Warum verschachtelte Klassen verwenden?

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.


26

Ich denke, die Konvention, die allgemein befolgt wird, ist folgende:

  • Die statische Klasse innerhalb einer Klasse der obersten Ebene ist eine verschachtelte Klasse
  • Eine nicht statische Klasse innerhalb einer Klasse der obersten Ebene ist eine innere Klasse , die zwei weitere Formen hat:
    • Lokale Klasse - benannte Klassen, die innerhalb eines Blocks wie eine Methode oder ein Konstruktorkörper deklariert sind
    • anonyme Klasse - unbenannte Klassen, deren Instanzen in Ausdrücken und Anweisungen erstellt werden

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.


15

Verschachtelte Klasse: Klasse innerhalb der Klasse

Typen:

  1. Statisch verschachtelte Klasse
  2. Nicht statische verschachtelte Klasse [Innere Klasse]

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);

13

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.


2
Der erste Satz ist falsch. Es gibt nicht so etwas wie ‚ die Instanz der inneren Klasse‘ und Instanzen davon können jederzeit erstellt werden , nachdem die äußeren Klasse instanziiert wurde. Der zweite Satz folgt nicht aus dem ersten Satz.
Marquis von Lorne

11

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.


10

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.


2
'statisches Inneres' ist ein Widerspruch.
Marquis von Lorne

5
Es ist keine Konvention, die die innere Klasse als nicht statisch verschachtelte Klasse definiert, sondern die JLS. docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Lew Bloch

1
Und die Begriffe werden nicht "synonym verwendet".
Marquis von Lorne

warum statisch im obigen Beispiel Fehler in ide geben
DeV

10

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….
  }
}

1
'statisches Inneres' ist ein Widerspruch. Eine verschachtelte Klasse ist entweder statisch oder innerlich.
Marquis von Lorne

9

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();




8

Ä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.


3
Gemäß der Java-Dokumentation gibt es einen Unterschied zwischen einer inneren Klasse und einer statisch verschachtelten Klasse - statisch verschachtelte Klassen haben keine Verweise auf ihre einschließende Klasse und werden hauptsächlich für Organisationszwecke verwendet. Sie sollten Jegschemeschs Antwort für eine ausführlichere Beschreibung sehen.
Mipadi

1
Ich denke, der semantische Unterschied ist größtenteils historisch. Als ich einen C # -> Java 1.1-Compiler schrieb, war die Java-Sprachreferenz sehr explizit: Verschachtelte Klasse ist statisch, innere Klasse nicht (und hat daher diese $ 0). Auf jeden Fall ist es verwirrend und ich bin froh, dass es kein Problem mehr ist.
Tomer Gabel

2
Das JLS definiert "innere Klasse" in docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3, und deshalb ist es unmöglich, eine nicht statische "innere" zu haben Klasse "in Java. "Verschachtelt" ist NICHT "nur ein anderer Begriff, der dasselbe bedeutet", und es ist NICHT WAHR, dass "eine innere Klasse eine Klasse ist, die innerhalb einer Klasse definiert ist (statisch oder nicht)". Das sind falsche Informationen.
Lew Bloch

6

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:

  • Die innere Klasse ist ein bestimmter Typ einer verschachtelten Klasse
  • innere Klassen sind Teilmengen verschachtelter Klassen
  • Sie können sagen, dass eine innere Klasse auch eine verschachtelte Klasse ist, aber Sie können NICHT sagen, dass eine verschachtelte Klasse auch eine innere Klasse ist .

Spezialität der inneren Klasse:

  • Die Instanz einer inneren Klasse hat Zugriff auf alle Mitglieder der äußeren Klasse, auch auf diejenigen, die als "privat" gekennzeichnet sind.


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:

  • Die statische innere Klasse hätte nur Zugriff auf die statischen Elemente der äußeren Klasse und keinen Zugriff auf nicht statische Elemente.

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.



6

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


2
"Statisch verschachtelte Klasse kann nicht auf nicht statische (Instanz-) Datenelemente oder Methoden zugreifen." ist falsch und verursacht Verwirrung . Sie haben absolut Zugriff auf private Instanzinformationen - vorausgesetzt, sie erstellen eine Instanz, auf die sie auf diese Instanzinformationen zugreifen können. Sie haben keine einschließende Instanz wie innere Klassen, aber sie haben Zugriff auf die privaten Mitglieder der Instanz ihrer einschließenden Klasse.
TJ Crowder

5

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).


2
Das ist alles Unsinn. Dies zeigt nur, dass eine innere Klasse keine statische Klasse enthalten kann. Der Teil über 'hängt nicht davon ab, welche Klasse er enthält' ist bedeutungslos, ebenso wie der folgende Satz.
Marquis von Lorne

5

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);
        }
    }
}

"Wenn wir eine statische Elementklasse innerhalb einer Klasse deklarieren, wird sie als verschachtelte Klasse der obersten Ebene bezeichnet." Das macht keinen Sinn. "Eine Klasse der obersten Ebene ist eine Klasse, die keine verschachtelte Klasse ist." Es gibt keine "verschachtelte Klasse der obersten Ebene".
Radiodef

3

Das Folgende ist ein Beispiel für static nested classund 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()); 

    }

}

3

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

  1. Eine statische Nestklasseninstanz kann vor der äußeren Klasse erstellt werden.

  2. Im Builder-Muster ist der Builder eine Hilfsklasse, mit der das Bankkonto erstellt wird.

  3. BankAccount.Builder ist nur mit BankAccount verknüpft. Keine anderen Klassen beziehen sich auf BankAccount.Builder. Daher ist es besser, sie zusammen zu organisieren, ohne die Namenskonvention zu verwenden.
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:

  1. Innere Klasse MyAdapter muss auf das äußere Klassenmitglied zugreifen.

  2. 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
        }
    }
}

2

Ein Diagramm

Geben Sie hier die Bildbeschreibung ein

Der Hauptunterschied zwischen static nestedund non-static nestedKlassen besteht darin, dass static nested kein Zugriff auf nicht statische äußere Klassenmitglieder besteht


0

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.


1
"... sagt, dass es sich um ein statisches Mitglied der äußeren Klasse handelt, was bedeutet ...": Es ist nicht falsch, sich eine statisch verschachtelte Klasse als "Mitgliedsklasse" der äußeren Klasse vorzustellen, sondern die Ähnlichkeiten mit statischen Feldern und Methoden enden dort. Eine statisch verschachtelte Klasse "gehört" nicht zur äußeren Klasse. In fast jeder Hinsicht ist eine statisch verschachtelte Klasse eine freistehende Klasse der obersten Ebene, deren Klassendefinition zur Vereinfachung der Verpackung in die der äußeren Klasse verschachtelt wurde (und hoffentlich, weil zwischen der verschachtelten Klasse und der äußeren Klasse eine logische Zuordnung besteht ... obwohl es keinen geben muss).
Scottb

1
'statisches Inneres' ist ein Widerspruch. Statische Klassen existieren auf der ersten Verschachtelungsebene und sind per Definition keine inneren Klassen. Sehr verwirrt.
Marquis von Lorne

0

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

  1. Auf diese Weise können Klassen, die nur an einer Stelle verwendet werden, logisch gruppiert werden.
  2. Es erhöht die Einkapselung.
  3. Dies kann zu besser lesbarem und wartbarem Code führen.

Quelle: Die Java ™ -Tutorials - Verschachtelte Klassen


-1

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.


1
Das ist falsch. Es gibt eine spezielle Syntax zum Erstellen einer inneren Klasse außerhalb des Bereichs der einschließenden Klasse.
Marquis von Lorne

-1

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


-2

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);
                        }*/
                    //}
                }
    }

1
Offensichtlich der Codeteil. Und falls Sie es nicht bemerkt haben: Ihr Codebeispiel ist super schwer zu lesen. Sogar auf meinem riesigen Desktop-Monitor habe ich eine horizontale Bildlaufleiste. Stellen Sie Ihre Kommentare über oder unter das, was sie kommentieren - anstatt hinter .
GhostCat
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.