Was ist der Hauptunterschied zwischen einer inneren Klasse und einer statischen verschachtelten Klasse in Java? Spielt der Entwurf/die Implementierung eine Rolle bei der Wahl einer dieser beiden Klassen?
Antworten
Zu viele Anzeigen?Die Begriffe werden austauschbar verwendet. Wenn Sie wirklich pedantisch sein wollen, dann müssen Sie könnte Definieren Sie "verschachtelte Klasse", um eine statische innere Klasse zu bezeichnen, die keine umschließende Instanz hat. Im Code könnten Sie etwas wie dieses haben:
public class Outer {
public class Inner {}
public static class Nested {}
}
Diese Definition ist jedoch nicht wirklich allgemein anerkannt.
Ich glaube nicht, dass es hier viel hinzuzufügen gibt, die meisten Antworten erklären perfekt die Unterschiede zwischen statisch verschachtelten Klassen und inneren Klassen. Bei der Verwendung von verschachtelten Klassen im Vergleich zu inneren Klassen ist jedoch folgendes zu beachten. Wie in einigen Antworten erwähnt, können innere Klassen nicht ohne eine Instanz der sie umschließenden Klasse instanziiert werden, was bedeutet, dass sie HALTEN a Zeiger auf die Instanz der sie umschließenden Klasse, was zu einem Speicherüberlauf oder einer Stack Overflow Exception führen kann, da die GC nicht in der Lage ist, die umschließenden Klassen zu sammeln, auch wenn sie nicht mehr verwendet werden. Um dies zu verdeutlichen, schauen Sie sich den folgenden Code an:
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 // inner = null;
Das Programm wird die " Ich bin zerstört! ", aber wenn man diesen Kommentar beibehält, ist das nicht der Fall.
Der Grund dafür ist, dass weiße innere Instanz noch referenziert wird GC kann es nicht sammeln und weil es verweist (hat einen Zeiger auf) die äußere Instanz ist es nicht zu sammeln. Wenn Sie genug von diesen Objekten in Ihrem Projekt haben, kann Ihnen der Speicher ausgehen.
Im Vergleich zu statischen inneren Klassen, die keinen Punkt auf die innere Klasseninstanz halten, weil sie nicht instanzbezogen, sondern klassenbezogen sind. Das obige Programm kann ausgeben " Ich bin zerstört! ", wenn Sie die Klasse Inner statisch machen und sie mit Outer.Inner i = new Outer.Inner();
Bei der Erstellung einer Instanz wird die Instanz der nicht statischen inneren Klasse mit der Referenz des Objekts der äußeren Klasse erstellt, in der es definiert ist. Diese bedeutet, dass sie eine einschließende Instanz hat. Aber die Instanz der statischen inneren Klasse wird mit der Referenz der äußeren Klasse erstellt, nicht mit der Referenz des Objekts der äußeren Klasse. Dies bedeutet, dass sie dass sie keine einschließende Instanz hat.
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….
}
}
Ähm... eine innere Klasse IST eine verschachtelte Klasse... meinen Sie anonyme Klasse und innere Klasse?
Bearbeiten: Wenn Sie tatsächlich inner vs anonyme gemeint... eine innere Klasse ist nur eine Klasse innerhalb einer Klasse wie definiert:
public class A {
public class B {
}
}
Eine anonyme Klasse hingegen ist eine Erweiterung einer anonym definierten Klasse, so dass keine eigentliche "Klasse" definiert wird, wie in:
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
Weiter bearbeiten:
Wikipedia behauptet, dass es einen Unterschied gibt in Java, 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 keine Referenzen gibt, um die Behauptung zu untermauern... unterm Strich ist eine innere Klasse eine Klasse, die innerhalb einer Klasse (statisch oder nicht) definiert ist, und verschachtelt ist nur ein anderer Begriff, um das Gleiche zu meinen.
Es gibt einen feinen Unterschied zwischen statischen und nicht-statischen verschachtelten Klassen... nicht-statische innere Klassen haben impliziten Zugriff auf Instanzfelder und Methoden der umschließenden Klasse (daher können sie nicht in einem statischen Kontext konstruiert werden, es wird ein Compilerfehler sein). Statische verschachtelte Klassen hingegen haben keinen impliziten Zugriff auf Instanzfelder und -methoden und können in einem statischen Kontext konstruiert werden.
Ich denke, dass keine der obigen Antworten Ihnen den Unterschied zwischen einer verschachtelten Klasse und einer statischen verschachtelten Klasse in Bezug auf das Anwendungsdesign an einem echten Beispiel verdeutlicht. Der Hauptunterschied zwischen einer statischen verschachtelten Klasse und einer inneren Klasse ist die Fähigkeit, auf das Instanzfeld der äußeren Klasse zuzugreifen.
Schauen wir uns die beiden folgenden Beispiele an.
Statische Schachtelklasse: Ein gutes Beispiel für die Verwendung statischer verschachtelter Klassen ist das Builder-Muster ( https://dzone.com/articles/design-patterns-the-builder-pattern ).
Für BankAccount verwenden wir eine statische verschachtelte Klasse, hauptsächlich weil
-
Die Instanz der statischen Schachtelklasse kann vor der äußeren Klasse erstellt werden.
-
Im Builder-Muster ist der Builder eine Hilfsklasse, die zur Erstellung des Bankkontos verwendet wird.
-
BankAccount.Builder ist nur mit BankAccount verbunden. Keine anderen Klassen sind mit BankAccount.Builder verknüpft, so dass es besser ist, sie zusammen zu organisieren, ohne Namenskonventionen 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 die Definition eines Event-Handlers. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html
Für MyClass verwenden wir die innere Klasse, hauptsächlich weil:
-
Die innere Klasse MyAdapter muss auf die Mitglieder der äußeren Klasse zugreifen.
-
In diesem Beispiel ist MyAdapter nur mit MyClass verknüpft. Es gibt keine anderen Klassen, die mit MyAdapter verbunden sind. 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 } } }
99 Stimmen
Die Antwort von Joshua Bloch ist in Leistungsfähiges Java lesen
item 22 : Favor static member classes over non static
24 Stimmen
Für das Protokoll, es ist Punkt 24 in der 3. Auflage des gleichen Buches.