it-swarm.com.de

Statisch verschachtelte Klasse in Java, warum?

Ich habe den Code Java nach LinkedList durchsucht und festgestellt, dass eine statische verschachtelte Klasse Entry verwendet wurde.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

Was ist der Grund für die Verwendung einer statischen verschachtelten Klasse anstelle einer normalen inneren Klasse?

Der einzige Grund, an den ich denken konnte, war, dass Entry keinen Zugriff auf Instanzvariablen hat, daher hat es aus Sicht von OOP) eine bessere Kapselung.

Aber ich dachte, es könnte andere Gründe geben, vielleicht die Leistung. Was könnte es sein?

Hinweis. Ich hoffe, ich habe meine Begriffe richtig verstanden, ich hätte es eine statische innere Klasse genannt, aber ich denke, das ist falsch: http://Java.Sun.com/docs/books/tutorial/Java/javaOO/ verschachtelt.html

203
David Turner

Die Sun-Seite, auf die Sie verlinken, weist einige wesentliche Unterschiede auf:

Eine verschachtelte Klasse ist ein Mitglied ihrer einschließenden Klasse. Nicht statische verschachtelte Klassen (innere Klassen) haben Zugriff auf andere Mitglieder der einschließenden Klasse, auch wenn sie als privat deklariert sind. Statisch verschachtelte Klassen haben keinen Zugriff auf andere Mitglieder der einschließenden Klasse.
...

Hinweis: Eine statisch verschachtelte Klasse interagiert mit den Instanzmitgliedern ihrer äußeren Klasse (und anderen Klassen) wie jede andere Klasse der obersten Ebene. Tatsächlich ist eine statisch verschachtelte Klasse eine Klasse der obersten Ebene, die aus Gründen der Vereinfachung des Packens in einer anderen Klasse der obersten Ebene verschachtelt wurde.

Es besteht keine Notwendigkeit für LinkedList.Entry als Klasse der obersten Ebene, wie sie only von LinkedList verwendet wird (es gibt auch einige andere Schnittstellen mit statisch verschachtelten Klassen mit dem Namen Entry, z wie Map.Entry - das gleiche Konzept). Und da es keinen Zugriff auf die Mitglieder von LinkedList benötigt, ist es sinnvoll, dass es statisch ist - es ist ein viel saubererer Ansatz.

Als Jon Skeet weist darauf hin halte ich es für eine bessere Idee, wenn Sie eine verschachtelte Klasse verwenden, damit zu beginnen, dass sie statisch ist, und dann zu entscheiden, ob sie wirklich nicht statisch sein muss Ihre Nutzung.

261
matt b

Meiner Meinung nach sollte die Frage immer umgekehrt sein, wenn man eine innere Klasse sieht - muss es wirklich eine innere Klasse sein, mit der zusätzlichen Komplexität und dem Impliziten (anstatt explizit und klarer) , IMO) Verweis auf eine Instanz der enthaltenden Klasse?

Wohlgemerkt, ich bin voreingenommen als C # -Fan - C # hat nicht das Äquivalent von inneren Klassen, obwohl es verschachtelte Typen hat. Ich kann nicht sagen, dass ich innere Klassen noch verpasst habe :)

44
Jon Skeet

Hier sind nicht offensichtliche Probleme mit der Speicherbindung zu berücksichtigen. Da eine nicht statische innere Klasse einen impliziten Verweis auf die äußere Klasse beibehält, wird auch auf die äußere Instanz stark verwiesen, wenn auf eine Instanz der inneren Klasse stark verwiesen wird. Dies kann zu Kopfkratzern führen, wenn in der äußeren Klasse kein Müll gesammelt wird, obwohl es scheint nichts darauf verweist.

26
Leigh

Zum einen haben nicht-statische innere Klassen ein zusätzliches, verstecktes Feld, das auf die Instanz der äußeren Klasse verweist. Wenn die Entry-Klasse also nicht statisch wäre, würde sie neben dem Zugriff, den sie nicht benötigt, vier statt drei Zeiger enthalten.

In der Regel würde ich sagen, wenn Sie eine Klasse definieren, die im Grunde genommen als Sammlung von Datenelementen fungiert, wie z. B. eine "Struktur" in C, sollten Sie überlegen, sie statisch zu machen.

10
DavidLG

Statische innere Klasse wird im Builder-Muster verwendet. Eine statische innere Klasse kann eine äußere Klasse instanziieren, die nur einen privaten Konstruktor hat. Sie können also eine statische innere Klasse verwenden, um die äußere Klasse zu instanziieren, die nur einen privaten Konstruktor hat. Mit der inneren Klasse können Sie nicht dasselbe tun, da Sie vor dem Zugriff auf die innere Klasse ein Objekt der äußeren Klasse erstellen müssen.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

Dies gibt x: 1 aus

7
seenimurugan

statische verschachtelte Klassen sind wie jede andere äußere Klasse, da sie keinen Zugriff auf Mitglieder der äußeren Klasse haben.

Nur zur Vereinfachung des Packens können wir statische verschachtelte Klassen aus Gründen der Lesbarkeit in eine äußere Klasse einteilen. Davon abgesehen gibt es keinen anderen Anwendungsfall für statisch verschachtelte Klassen.

Ein Beispiel für eine solche Verwendung finden Sie in Android R.Java (Ressourcen) -Datei. Res-Ordner von Android enthält Layouts (mit Bildschirmdesigns), Zeichenordner (mit Bildern, die für das Projekt verwendet werden), Werteordner (der Zeichenfolgenkonstanten enthält) usw.

Da alle Ordner Teil des Ordners Res sind, generiert das Tool Android) eine R.Java-Datei (Ressourcen), die intern viele statische verschachtelte Klassen für jeden ihrer inneren Ordner enthält.

Hier ist das Aussehen und Verhalten der in Android generierten R.Java-Datei: Hier werden sie nur zur Vereinfachung der Verpackung verwendet.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}
7
user1923551

From http://docs.Oracle.com/javase/tutorial/Java/javaOO/whentouse.html :

Verwenden Sie eine nicht statische verschachtelte Klasse (oder innere Klasse), wenn Sie Zugriff auf die nicht öffentlichen Felder und Methoden einer einschließenden Instanz benötigen. Verwenden Sie eine statische verschachtelte Klasse, wenn Sie diesen Zugriff nicht benötigen.

6
John29

Einfaches Beispiel:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Wenn die Klasse nicht statisch ist, kann sie nur in einer Instanz der oberen Klasse instanziiert werden (also nicht in dem Beispiel, in dem main eine statische Funktion ist).

4
Vinze

Einer der Gründe für statisches vs. normales Verhalten ist das Laden von Klassen. Sie können eine innere Klasse nicht im Konstruktor ihres übergeordneten Elements instanziieren.

PS: Ich habe immer verstanden, dass 'verschachtelt' und 'inner' austauschbar sind. Es mag subtile Nuancen in den Begriffen geben, aber die meisten Java Entwickler würden beides verstehen.

2
Mark Renouf

Nicht statische innere Klassen können zu Speicherverlusten führen, während statische innere Klassen dagegen schützen. Wenn die äußere Klasse beträchtliche Daten enthält, kann dies die Leistung der Anwendung verringern.

1
The Gun

Wenn Sie eine statische verschachtelte Klasse anstelle einer nicht statischen verwenden, können in einigen Fällen Leerzeichen gespart werden. Beispiel: Implementieren Sie ein Comparator in einer Klasse, sagen Sie Student.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

Dann stellt static sicher, dass die Student-Klasse nur einen Komparator hat, anstatt bei jeder Erstellung einer neuen Student-Instanz einen neuen zu instanziieren.

0
JenkinsY

Ich weiß nichts über Leistungsunterschiede, aber wie Sie sagen, ist eine statisch verschachtelte Klasse kein Teil einer Instanz der einschließenden Klasse. Es scheint einfacher zu sein, eine statische verschachtelte Klasse zu erstellen, es sei denn, Sie benötigen sie wirklich, um eine innere Klasse zu sein.

Es ist ein bisschen wie das, warum ich meine Variablen immer in Java - final mache, wenn sie nicht final sind, weiß ich, dass mit ihnen etwas Komisches los ist. Wenn Sie eine innere Klasse anstelle einer statischen verwenden verschachtelte Klasse, sollte es einen guten Grund geben.

0
Juri Pakaste