Wenn ich versuche, den folgenden Code zu kompilieren, bekomme ich den Kompilierungsfehler:
%Vor% %Vor% Aber, wenn ich new Test().C.i
in new Test().new C().i
ändere, kompiliert es einfach gut.
Warum? Wenn ich in C statisch bin, sollte ich C nicht instanziieren müssen. Ich sollte es nur durch die Klasse C und nicht durch ein C-Objekt aufrufen können.
Was vermisse ich?
Das Problem ist, dass "." Identifier
in der Java-Syntax erwartet, dass der Bezeichner auf eine Variable und nicht auf einen Typ verweist.
Dies wird in 6.5.6.2. Qualified Expression Names
der JLS (unter anderem) angegeben:
Wenn Q ein Typname ist, der einen Klassentyp (§8 (Klassen)) nennt, dann:
Wenn es nicht genau ein zugreifbares (§6.6) Mitglied der Klasse gibt Geben Sie ein Feld namens ID ein, dann tritt ein Fehler bei der Kompilierung auf.
Andernfalls, wenn das einzelne zugängliche Memberfeld keine Klasse ist Variable (das heißt, es ist nicht als statisch deklariert), dann eine Kompilierzeit Fehler tritt auf.
Andernfalls wird, wenn die Klassenvariable als final deklariert wird, Q.Id bezeichnet der Wert der Klassenvariablen.
Der Typ des Ausdrucks Q.Id ist der deklarierte Typ der Klasse Variable nach Capture-Konvertierung (§5.1.10).
Wenn Q.Id in einem Kontext erscheint, der eine Variable und keinen Wert benötigt, dann tritt ein Fehler bei der Kompilierung auf.
Ansonsten bezeichnet Q.Id die Klassenvariable.
Der Typ des Ausdrucks Q.Id ist der deklarierte Typ der Klasse Variable nach Capture-Konvertierung (§5.1.10).
Beachten Sie, dass diese Klausel die Verwendung von Enum-Konstanten (§8.9) umfasst, da diese haben immer eine entsprechende letzte Klassenvariable.
Obwohl ich die Logik, warum Sie denken würden, dass es so funktionieren würde, wirklich schätzen würde - ich habe eigentlich erwartet, dass es auch so funktioniert -, ist das keine große Sache: Da gibt es immer genau nur ein i
Sie kann sich auf Test.C.i
beziehen. Wenn i
nicht statisch ist, ist new Test().new C().i
der richtige Weg, um darauf zuzugreifen.
Eine andere Möglichkeit, es zu betrachten, ist 15.8. Primary Expressions mit der eigentlichen Syntax für primäre Ausdrücke (mit der wir hier umgehen): Erlaubt ClassInstanceCreationExpression
(weshalb new Test().new C().i
funktioniert) sowie FieldAccess
(was für% co_de funktioniert % weil die "Klasse" rekursiv aufgelöst wird - nur der letzte Bezeichner muss sich dann auf ein Feld beziehen.)
Ich denke, der Grund, warum new Test().new C().i
funktioniert, ist, weil die Klasse Test eine Klasse der obersten Ebene ist und als static
behandelt wird. Wenn Sie Ihre innere Klasse C
auf statisch ändern würden, dann würde new C().i
funktionieren.
Sie sollten jedoch NICHT auf statische Elemente auf nicht statische Weise zugreifen.
Um auf Ihr statisches Feld zuzugreifen, tun Sie:
%Vor%Bearbeiten:
Diejenigen, die sagen, dass die Klasse Test
nicht statisch ist, finden Sie in dieser stackoverflow Antwort .
Alle Klassen der obersten Ebene sind per Definition statisch.
Worauf es ankommt, ist eine Instanz der Klasse eigenständig stehen. Oder umgekehrt: eine nicht statische innere Klasse (= Instanz innere Klasse) kann ohne eine Instanz des äußeren nicht existieren Klasse. Da eine Klasse auf oberster Ebene keine äußere Klasse hat, kann sie nicht sei alles andere als statisch.
Da alle Klassen der obersten Ebene statisch sind und das Schlüsselwort static in haben Eine Top-Level-Klassendefinition ist sinnlos.
Um Ihnen zu zeigen, wie blöd eine Idee ist, auf ein statisches Feld zuzugreifen, habe ich das folgende Projekt erstellt:
%Vor%Wenn Sie die Klasse kompilieren und in jd-gui anzeigen, können Sie sehen, wie sie kompiliert wurde:
%Vor%