wake-up-neo.com

Warum können wir keine statische Methode in einer (nicht statischen) inneren Klasse haben?

Warum können wir keine statische Methode in einer nicht statischen inneren Klasse haben? 

Wenn ich die innere Klasse statisch mache, funktioniert es. Warum ?

136
Rahul Garg

Da eine Instanz einer inneren Klasse implizit mit einer Instanz ihrer äußeren Klasse verknüpft ist, kann sie selbst keine statischen Methoden definieren. Da eine statische verschachtelte Klasse nicht direkt auf Instanzvariablen oder Methoden verweisen kann, die in ihrer umgebenden Klasse definiert sind, kann sie nur über eine Objektreferenz verwendet werden. Statische Methoden können daher in einer statischen verschachtelten Klasse deklariert werden.

105
Bill the Lizard

Es macht wenig Sinn, eine statische Methode in einer nicht statischen inneren Klasse zuzulassen. wie würden sie darauf zugreifen Sie können (zumindest anfangs) nicht auf eine nicht statische Instanz der inneren Klasse zugreifen, ohne eine Instanz der äußeren Klasse zu durchlaufen. Es gibt keine rein statische Möglichkeit, eine nicht statische innere Klasse zu erstellen.

Für eine äußere Klasse Outer können Sie auf eine statische Methode test() wie folgt zugreifen:

Outer.test();

Für eine statische innere Klasse Inner können Sie wie folgt auf die statische Methode innerTest() zugreifen:

Outer.Inner.innerTest();

Wenn Inner jedoch nicht statisch ist, gibt es jetzt keinen rein statischen Weg, auf die Methode innertest zu verweisen. Nicht statische innere Klassen sind an eine bestimmte Instanz ihrer äußeren Klasse gebunden. Eine Funktion unterscheidet sich von einer Konstanten dahingehend, dass garantiert ist, dass ein Verweis auf Outer.Inner.CONSTANT so eindeutig ist, dass ein Funktionsaufruf Outer.Inner.staticFunction(); dies nicht ist. Nehmen wir an, Sie haben Inner.staticFunction(), das getState() aufruft, das in Outer definiert ist. Wenn Sie versuchen, diese statische Funktion aufzurufen, haben Sie jetzt einen mehrdeutigen Verweis auf die innere Klasse. Das heißt, auf welcher Instanz der inneren Klasse rufen Sie die statische Funktion auf? Es ist wichtig. Es gibt keine wirklich statische Methode, um auf diese statische Methode zu verweisen, da dies implizit auf das äußere Objekt verweist.

Paul Bellora hat Recht, dass die Sprachdesigner dies hätten zulassen können. Sie müssen dann in statischen Methoden der nicht statischen inneren Klasse jeden Zugriff auf den impliziten Verweis auf die äußere Klasse sorgfältig unterbinden. Welchen Wert hat es an diesem Punkt, eine innere Klasse zu sein, wenn Sie die äußere Klasse nur statisch referenzieren können? Und wenn der statische Zugriff in Ordnung ist, warum dann nicht die gesamte innere Klasse für statisch erklären? Wenn Sie die innere Klasse einfach statisch machen, haben Sie keinen impliziten Verweis auf die äußere Klasse, und Sie haben diese Mehrdeutigkeit nicht mehr.

Wenn Sie tatsächlich need statische Methoden für eine nicht statische innere Klasse verwenden, müssen Sie wahrscheinlich Ihr Design überdenken.

44
Eddie

Ich habe eine Theorie, die möglicherweise richtig ist oder nicht.

Zunächst sollten Sie wissen, wie innere Klassen in Java implementiert werden. Angenommen, Sie haben diese Klasse:

class Outer {
    private int foo = 0;
    class Inner implements Runnable {
        public void run(){ foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(); }
}

Wenn Sie es kompilieren, sieht der generierte Bytecode so aus, als ob Sie so etwas schreiben würden:

class Outer {
    private int foo = 0;
    static class Inner implements Runnable {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public void run(){ this$0.foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(this); }
}

Wenn wir nun statische Methoden in nicht statischen inneren Klassen zulassen, möchten Sie vielleicht so etwas tun.

class Outer {
    private int foo = 0;
    class Inner {
        public static void incrFoo(){ foo++; }
    }
}

... was ziemlich vernünftig erscheint, da die Inner-Klasse eine Inkarnation pro Outer-Instanz zu haben scheint. Aber wie wir oben gesehen haben, sind die nicht statischen inneren Klassen wirklich nur syntaktischer Zucker für statische "innere" Klassen, daher wäre das letzte Beispiel ungefähr äquivalent zu:

class Outer {
    private int foo = 0;
    static class Inner {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public static void incrFoo(){ this$0.foo++; }
    }
}

... was offensichtlich nicht funktioniert, da this$0 nicht statisch ist. Diese Art erklärt, warum statische Methoden nicht zulässig sind (obwohl Sie das Argument angeben könnten, dass Sie statische Methoden zulassen könnten, solange sie nicht auf das umgebende Objekt verweisen) und warum Sie keine statischen Endfelder ( Es wäre kontraintuitiv, wenn Instanzen nicht statischer innerer Klassen von verschiedenen Objekten den "statischen Zustand" gemeinsam nutzen. Außerdem wird erläutert, warum die endgültigen Felder are zulässig sind (sofern sie nicht auf das umgebende Objekt verweisen).

20
gustafc

Der einzige Grund ist "kein Muss". Warum also die Mühe machen, es zu unterstützen?

Syntaktisch gibt es keinen Grund, einer inneren Klasse statische Member zuzuweisen. Obwohl eine Instanz von Inner mit einer Instanz von Outer verknüpft ist, können Sie mit Outer.Inner.myStatic ein statisches Mitglied von Inner referenzieren, wenn Java dies wünscht.

Wenn Sie etwas unter allen Instanzen von Inner freigeben müssen, können Sie sie einfach als statische Member in Outer einfügen. Dies ist nicht schlimmer als Sie statische Member in Inner verwenden, wobei Outer trotzdem auf jedes private Member von Inner zugreifen kann (Verbesserung der Einkapselung nicht).

Wenn Sie etwas unter allen Instanzen von Inner freigeben müssen, die von einem outer-Objekt erstellt wurden, ist es sinnvoller, sie als normale Mitglieder in die Outer-Klasse aufzunehmen.

Ich stimme der Meinung nicht zu, dass "eine statisch verschachtelte Klasse nur eine Klasse der Spitzenklasse ist". Ich denke, es ist besser, eine statisch verschachtelte Klasse/innere Klasse als Teil der äußeren Klasse zu betrachten, da sie auf private Mitglieder der äußeren Klasse zugreifen können. Und Mitglieder der äußeren Klasse sind auch "Mitglieder der inneren Klasse". Es ist also nicht nötig, statische Member in der inneren Klasse zu unterstützen. Ein ordentliches/statisches Mitglied in der äußeren Klasse wird ausreichen.

6
Don Li

Kurze Antwort: Das mentale Modell, das die meisten Programmierer haben, ist nicht das von Javac verwendete Modell. Die Anpassung an das intuitivere Modell hätte eine große Änderung der Funktionsweise von Javac erfordert.

Der Hauptgrund dafür, dass statische Member in inneren Klassen wünschenswert sind, ist die Sauberkeit des Codes. Ein statisches Member, das nur von einer inneren Klasse verwendet wird, sollte in ihr leben und muss nicht in der äußeren Klasse platziert werden. Erwägen:

class Outer {
   int outID;

   class Inner {
      static int nextID;
      int id = nextID++;

      String getID() {
         return outID + ":" + id;
      }
   }
}

Bedenken Sie, was in getID () vor sich geht, wenn ich den unqualifizierten Bezeichner "outID" verwende. Der Bereich, in dem diese Kennung angezeigt wird, sieht etwa so aus:

Outer -> Inner -> getID()

Auch hier, weil javac genau so funktioniert, umfasst die "Outer" -Ebene des Gültigkeitsbereichs sowohl statische als auch Instanzmitglieder von Outer. Dies ist verwirrend, da uns normalerweise gesagt wird, dass wir den statischen Teil einer Klasse als eine andere Ebene des Bereichs betrachten sollen:

Outer static -> Outer instance -> instanceMethod()
         \----> staticMethod()

Bei dieser Denkweise kann staticMethod () natürlich nur statische Member von Outer sehen. Wenn javac auf diese Weise funktioniert, führt das Referenzieren einer Instanzvariablen in einer statischen Methode zu einem Fehler "Name kann nicht aufgelöst werden". Was wirklich passiert, ist, dass der Name im Gültigkeitsbereich gefunden wird, aber dann kommt eine zusätzliche Check-Ebene hinzu und stellt fest, dass der Name in einem Instanzkontext deklariert wurde und aus einem statischen Kontext referenziert wird.

OK, wie bezieht sich das auf innere Klassen? Naiv, wir glauben, dass es keinen Grund gibt, dass innere Klassen keinen statischen Gültigkeitsbereich haben können, weil wir uns vorstellen, dass der Geltungsbereich folgendermaßen funktioniert:

Outer static -> Outer instance -> Inner instance -> getID()
         \------ Inner static ------^

Mit anderen Worten, statische Deklarationen in der inneren Klasse und Instanzdeklarationen in der äußeren Klasse liegen beide innerhalb des Instanzkontexts der inneren Klasse, aber keine davon ist tatsächlich in der anderen Klasse verschachtelt. Beide sind stattdessen im statischen Bereich von Outer verschachtelt.

So funktioniert javac nicht - es gibt eine einzige Ebene für statische und Instanzmitglieder, und der Bereich ist immer streng verschachtelt. Sogar Vererbung wird implementiert, indem Deklarationen in die Unterklasse kopiert werden, anstatt den Superklassenbereich zu verzweigen und zu durchsuchen.

Um statische Member innerer Klassen zu unterstützen, müsste javac entweder statische Bereiche und Instanzbereiche und unterstützen, um Zweighierarchien zu verzweigen und wieder zu verbinden, oder es müsste seine einfache boolesche "statische Kontext" - Idee erweitern, um den Typ zu verfolgen Kontext auf allen Ebenen verschachtelter Klassen im aktuellen Bereich.

3

Warum können wir keine statische Methode in einer nicht statischen inneren Klasse haben?

Hinweis: Eine nicht statische verschachtelte Klasse wird als innere Klasse bezeichnet. Daher haben Sie non-static inner class nicht als solche.

Eine Instanz der inneren Klasse hat keine Existenz ohne eine entsprechende Instanz der äußeren Klasse. Eine innere Klasse kann keine anderen statischen Member als Kompilierungszeitkonstanten deklarieren. Wenn dies erlaubt wäre, hätte es eine Mehrdeutigkeit hinsichtlich der Bedeutung von static gegeben. In diesem Fall hätte es einige Verwirrungen gegeben:

  1. Bedeutet das, dass es nur eine Instanz in VM gibt?
  2. Oder nur eine Instanz pro Objekt?

Deshalb haben sich die Designer wahrscheinlich entschieden, dieses Problem überhaupt nicht zu lösen.

Wenn ich die innere Klasse statisch mache, funktioniert es. Warum ?

Auch hier können Sie keine innere Klasse statisch machen, sondern eine statische Klasse als verschachtelt deklarieren. In diesem Fall ist diese verschachtelte Klasse tatsächlich Teil der äußeren Klasse und kann ohne Probleme statische Member enthalten.

3
i_am_zero

Dieses Thema hat bei vielen die Aufmerksamkeit auf sich gezogen, dennoch werde ich versuchen, es auf einfachste Weise zu erklären.

Zunächst wird mit Bezug auf http://docs.Oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 eine Klasse oder Schnittstelle unmittelbar vor dem initialisiert Erstes Auftreten/Aufrufen eines Mitglieds, dem das statische Schlüsselwort vorangeht. 

  1. Wenn wir also ein statisches Element innerhalb einer inneren Klasse akzeptieren, führt dies zur Initialisierung der inneren Klasse, nicht notwendigerweise der äußeren/umschließenden Klasse. Daher behindern wir die Klasseninitialisierungssequenz.

  2. Berücksichtigen Sie auch die Tatsache, dass eine nicht statische innere Klasse der Instanz einer umschließenden/äußeren Klasse zugeordnet ist. Das Zuordnen zu einer Instanz bedeutet also, dass die innere Klasse in einer äußeren Klasseninstanz vorhanden ist und zwischen den Instanzen unterschiedlich ist. 

Um den Punkt zu vereinfachen, benötigen wir zum Zugriff auf das statische Member eine Instanz einer Outer-Klasse, von der aus wir erneut eine Instanz einer nicht-statischen inneren Klasse erstellen müssen. Statische Member sollten nicht an Instanzen gebunden sein und daher wird ein Kompilierungsfehler angezeigt. 

3
Doomed93

Eine innere Klasse ist etwas völlig anderes als eine statisch verschachtelte Klasse, obwohl beide in der Syntax ähnlich sind. Statisch verschachtelte Klassen sind nur ein Mittel zum Gruppieren, während innere Klassen eine starke Assoziation haben und auf alle Werte ihrer äußeren Klasse zugreifen. Sie sollten sicher sein, warum Sie eine innere Klasse verwenden möchten, und dann sollte es ganz natürlich sein, welche Sie verwenden müssen. Wenn Sie eine statische Methode deklarieren müssen, ist dies wahrscheinlich eine statische verschachtelte Klasse.

2
B.E.

Von: https://docs.Oracle.com/javase/tutorial/Java/javaOO/nested.html

Wie bei Instanzmethoden und -variablen ist eine innere Klasse einer Instanz ihrer umgebenden Klasse zugeordnet und hat direkten Zugriff auf die Methoden und Felder dieses Objekts. Da eine innere Klasse einer Instanz zugeordnet ist, kann sie selbst keine statischen Member definieren.

Orakels Erklärung ist oberflächlich und handwavy. Da es keinen technischen oder syntaktischen Grund gibt, statischen Mitgliedern innerhalb einer inneren Klasse vorzubeugen (dies ist in anderen Sprachen wie C # zulässig), war die Motivation der Java-Designer wahrscheinlich konzeptioneller Geschmack und/oder eine Frage der technischen Bequemlichkeit.

Hier ist meine Spekulation:

Im Gegensatz zu Klassen der obersten Ebene sind innere Klassen instanzabhängig: Eine Instanz innerer Klasse ist einer Instanz jeder äußeren Klasse zugeordnet und hat direkten Zugriff auf ihre Mitglieder. Dies ist die Hauptmotivation, sie in Java zu haben. Anders ausgedrückt: Eine innere Klasse ist für Instantiierung im Kontext einer äußeren Klasseninstanz. Ohne eine Instanz der äußeren Klasse sollte eine innere Klasse nicht mehr brauchbar sein als die anderen Instanzmitglieder der äußeren Klasse. Lassen Sie uns dies als den instanzabhängigen Geist innerer Klassen bezeichnen.

Die Beschaffenheit statischer Member (die NICHT objektorientiert sind) kollidiert mit dem instanzabhängigen - Geist innerer Klassen (die IS objektorientiert) sind, da Sie statische Member referenzieren/aufrufen können einer inneren Klasse ohne Instanz der äußeren Klasse unter Verwendung des qualifizierten inneren Klassennamens.

Insbesondere statische Variablen können auf eine andere Weise beleidigt werden: Zwei Instanzen einer inneren Klasse, die verschiedenen Instanzen der äußeren Klasse zugeordnet sind, teilen sich statische Variablen. Da Variablen eine Komponente des Status sind, teilen die beiden Instanzen der inneren Klasse den Status unabhängig von den Instanzen der äußeren Klasse, denen sie zugeordnet sind. Es ist nicht so, dass es nicht inakzeptabel ist, dass statische Variablen auf diese Weise funktionieren (wir akzeptieren sie in Java als einen vernünftigen Kompromiss für OOP Reinheit), aber es gibt wohl einen tieferen Verstoß, wenn man sie in inneren Klassen erlaubt, deren Instanzen es sind bereits durch Design mit Instanzen der äußeren Klasse gekoppelt. Das Verbot statischer Mitglieder innerhalb der inneren Klassen zugunsten des instanzabhängigen Geistes bringt den zusätzlichen Vorteil, dass diese tiefere OOP Straftat vorweggenommen wird.

Auf der anderen Seite werden statische Konstanten, die keinen Staat darstellen und keine zulässigen Zustände darstellen, zu einem solchen Verstoß geführt. Warum verbieten Sie nicht statische Konstanten für maximale Konsistenz mit dem instanzabhängigen Geist? Vielleicht, weil Konstanten nicht mehr Speicher als nötig beanspruchen muss (wenn sie nicht statisch sein müssen, werden sie in jede Instanz der inneren Klasse kopiert, die möglicherweise verschwenderisch ist). Ansonsten kann ich mir den Grund für die Ausnahme nicht vorstellen.

Es mag keine grundsolide Argumentation sein, aber IMO macht die kursive Bemerkung von Oracle in dieser Angelegenheit am sinnvollsten.

Zunächst einmal, warum jemand das statische Element in einer nicht statischen inneren Klasse definieren möchte? Antwort ist, so dass das äußere Klassenmitglied diese statischen Elemente nur mit dem inneren Klassennamen verwenden kann.

Aber für diesen Fall können wir das Mitglied direkt in der äußeren Klasse definieren. das mit allen Objekten der inneren Klasse innerhalb der Instanz der äußeren Klasse verknüpft wird.

wie unter Code,

public class Outer {

  class Inner {

    public static void method() {

    }

  }

}

kann so geschrieben werden 

public class Outer {

  void method() {

   }

   class Inner {


  }

}

Um den Code meiner Meinung nach nicht zu komplizieren, lässt der Java-Designer diese Funktionalität nicht zu, oder wir werden diese Funktionalität in zukünftigen Versionen möglicherweise mit weiteren Funktionen anzeigen. 

0
Vishnu Saini

Versuchen Sie, die Klasse als normales Feld zu behandeln. 

//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something 
0
user1888955

angenommen, es gibt zwei Instanzen der äußeren Klasse, und beide haben die innere Klasse instanziiert. Wenn die innere Klasse über ein statisches Member verfügt, wird nur eine Kopie dieses Members im Heap-Bereich aufbewahrt. In diesem Fall beziehen sich beide Objekte der äußeren Klasse darauf Einzelne Kopie & sie können es zusammen ändern. Dies kann zu "Dirty Read" -Situationen führen, um zu verhindern, dass Java diese Einschränkung anwendet. Ein weiterer starker Punkt zur Unterstützung dieses Arguments ist, dass Java statische Endmitglieder zulässt geändert von einem der äußeren Klassenobjekte .. Bitte lass es mich wissen, wenn ich falsch liege.

0
Malay