Ich habe gerade diesen seltsamen Code in einer anderen Frage gesehen. Ich dachte, es würde zu einem StackOverflowError
Werfen führen, aber es tut nicht ...
public class Node {
private Object one;
private Object two;
public static Node NIL = new Node(Node.NIL, Node.NIL);
public Node(Object one, Object two) {
this.one = one;
this.two = two;
}
}
Ich dachte, es würde explodieren, weil die Node.NIL
Referenzierung selbst erstellt werden sollte.
Ich kann nicht herausfinden, warum es nicht so ist.
java
stack-overflow
Anthony Raymond
quelle
quelle
static
aber ich bin nicht sicherNIL
Feld so aufgebaut ist, wie es deklariert wurdenew Node(null, null)
, denn wenn der Konstruktor aufgerufen wird,Node.NIL
wurde noch nichts festgelegt.Antworten:
NIL
ist eine statische Variable. Es wird einmal initialisiert, wenn die Klasse initialisiert wird. Bei der Initialisierung wird eine einzelneNode
Instanz erstellt. Die Erstellung davonNode
löst nicht die Erstellung andererNode
Instanzen aus, sodass es keine unendliche Kette von Aufrufen gibt. Das ÜbergebenNode.NIL
an den Konstruktoraufruf hat den gleichen Effekt wie das Übergebennull
, daNode.NIL
es beim Aufruf des Konstruktors noch nicht initialisiert ist. Daherpublic static Node NIL = new Node(Node.NIL, Node.NIL);
ist das gleiche wiepublic static Node NIL = new Node(null, null);
.Wenn es sich andererseits
NIL
um eine Instanzvariable handelt (und nicht als Argument an denNode
Konstruktor übergeben wurde, da der Compiler Sie in diesem Fall daran gehindert hätte, sie an den Konstruktor zu übergeben), wird sie jedes Mal initialisiert, wenn eine Instanz erstellt wird ofNode
wurde erstellt, wodurch eine neueNode
Instanz erstellt wurde, deren Erstellung eine andereNIL
Instanzvariable initialisierte , was zu einer unendlichen Kette von Konstruktoraufrufen führte, die enden würdenStackOverflowError
.quelle
NIL
es sich um eine Instanzvariable handelt, wird sie nicht mit dem Fehler kompiliertCannot reference a field before it is defined
.Node.NIL
an den Konstruktor übergeben wurde.Die Variable NIL erhält zuerst den Wert
null
und wird dann von oben nach unten initialisiert. Es ist keine Funktion und nicht rekursiv definiert. Jedes statische Feld, das Sie vor der Initialisierung verwenden, hat den Standardwert und Ihr Code ist der gleiche wiepublic static Node { public static Node NIL; static { NIL = new Node(null /*Node.NIL*/, null /*Node.NIL*/); } public Node(Object one, Object two) { // Assign values to fields } }
Dies unterscheidet sich nicht vom Schreiben
NIL = null; // set implicitly NIL = new Node(NIL, NIL);
Wenn Sie eine Funktion oder Methode wie diese definieren, erhalten Sie eine StackoverflowException
Node NIL(Node a, Node b) { return NIL(NIL(a, b), NIL(a, b)); }
quelle
Der Schlüssel zum Verständnis, warum es keine unendliche
Node
Initialisierung verursacht, besteht darin, dass die JVM bei der Initialisierung der Klasse den Überblick behält und eine Neuinitialisierung während eines rekursiven Verweises auf die Klasse innerhalb ihrer ursprünglichen Initialisierung vermeidet . Dies wird in diesem Abschnitt der Sprachspezifikation beschrieben :Während der statische Initialisierer die statische Instanz erstellt
NIL
, führt der Verweis aufNode.NIL
als Teil des Konstruktoraufrufs den statischen Initialisierer nicht erneut aus. Stattdessen verweist es nur auf den Wert, den die ReferenzNIL
zu diesem Zeitpunkt hat,null
in diesem Fall.quelle