Ich muss mehr als eine Stunde damit verbracht haben, den Grund für ein unerwartetes Verhalten herauszufinden. Ich stellte schließlich fest, dass ein Feld nicht so eingestellt war, wie ich es erwarten würde. Bevor ich zuhöre und weitermache, würde ich gerne verstehen, warum das so funktioniert.
Beim Ausführen des folgenden Beispiels würde ich erwarten, dass die Ausgabe wahr ist, aber sie ist falsch. Andere Tests zeigen, dass ich immer den Standardwert dieses Typs erhalte.
%Vor%Ausgabe:
%Vor%ist identisch mit
%Vor%Der Compiler verschiebt die Initialisierungen der Felder automatisch innerhalb des Konstruktors (direkt nach dem Aufruf des Superkonstruktors, implizit oder explizit).
Da der Standardwert eines booleschen Feldes false
ist, wenn super()
aufgerufen wird (und somit ClassOne()
und fireMethod()
), wurde bool
noch nicht auf true
gesetzt.
Fun Tatsache: der folgende Konstruktor
%Vor%wird als
verstanden %Vor%von der JVM, und die Ausgabe wird somit
sein %Vor% Der Superklassenkonstruktor wird vor dem Unterklassenkonstruktor aufgerufen. Und bevor ein Konstruktor ausgeführt wird, haben alle Instanzmitglieder in Java ihren Standardwert (false, 0, null). Wenn also super()
aufgerufen wird, ist bool
immer noch falsch (Standardwert für boolesche Werte).
Ganz allgemein ist das Aufrufen einer überschreibbaren Methode aus einem Konstruktor (in ClassOne) eine schlechte Idee für den Grund, den Sie gerade entdeckt haben: Sie könnten am Ende an einem Objekt arbeiten, das noch nicht vollständig initialisiert wurde.
Die Instanzinitialisierungen werden ausgeführt, nachdem super () implizit oder explizit aufgerufen wurde.
Aus der Java-Sprachspezifikation Abschnitt 12.5: "Erstellung von neuen Klasseninstanzen :
"3. Dieser Konstruktor beginnt nicht mit einem expliziten Konstruktoraufruf von ein anderer Konstruktor in der gleichen Klasse (mit diesem). Wenn dieser Konstruktor für eine andere Klasse als Object, dann beginnt dieser Konstruktor mit einem Explicit oder impliziter Aufruf eines Superklassenkonstruktors (mit super). Bewerten Argumente und verarbeiten diesen Superklassenkonstruktoraufruf rekursiv unter Verwendung derselben fünf Schritte. Wenn dieser Aufruf des Konstruktors abrupt abgeschlossen wird, dann Dieser Vorgang wird aus dem gleichen Grund abrupt beendet. Ansonsten, fahre fort mit Schritt 4.
"4. Führen Sie die Instanzinitialisierungen und Instanzvariableninitialisierungen für diese Klasse aus. Zuweisen der Werte der Instanzvariableninitialisierer zu den entsprechenden Instanzvariablen in der Reihenfolge von links nach rechts, in der sie textuell erscheinen der Quellcode für die Klasse. Wenn die Ausführung eines dieser Initialisierer erfolgt In einer Ausnahme werden dann keine weiteren Initialisierer und diese Prozedur verarbeitet schließt abrupt mit derselben Ausnahme ab. Fahren Sie andernfalls mit Schritt 5 fort. "
super()
ist in diesem Fall eigentlich überflüssig (Wortspiel nicht beabsichtigt), weil es implizit in jedem Konstruktor aufgerufen wird. Was das bedeutet ist, dass der Konstruktor von ClassOne
zuerst aufgerufen wird. Bevor also ein Konstruktor ausgeführt wird, haben die Instanzmitglieder ihre Standardwerte (also bool
ist false
). Es ist nur nach die Konstruktoren ausgeführt werden, dass die Felder initialisiert werden.
Ihr Konstruktor wird also effektiv:
%Vor% Aber ClassOne
ruft die überschreibbare Methode auf, die den Wert von bool
ausgibt, was an diesem Punkt false
ist.
Im Allgemeinen ist es eine schlechte Methode, überschreibbare Methoden von einem Konstruktor aus aufzurufen (wie Sie es in ClassOne
tun), weil Sie jetzt mit einem Objekt arbeiten, das nicht vollständig initialisiert ist.
Aus effektivem Java (2. Ausgabe):
Es gibt einige weitere Einschränkungen, die eine Klasse erfüllen muss, um Vererbung zuzulassen. Konstruktoren dürfen keine überschreibbaren Methoden direkt oder indirekt aufrufen. Wenn Sie diese Regel verletzen, führt dies zu einem Programmfehler. Der Superklassenkonstruktor wird vor dem Unterklassenkonstruktor ausgeführt, sodass die überschreibende Methode in der Unterklasse aufgerufen wird, bevor der Unterklassenkonstruktor ausgeführt wurde. Wenn die überschreibende Methode von einer vom Unterklassenkonstruktor durchgeführten Initialisierung abhängt, verhält sich die Methode nicht wie erwartet.
Die endgültige Antwort lautet: Verwenden Sie keine überschreibbare Methode in einem Konstruktor.
In jedem Konstruktor:
type field = value;
) Das macht das Leben interessant
%Vor%Dies führt zu
%Vor%a
auf 7 (für nichts) und b
auf 15 gesetzt. a
initialisiert. Meine IDE markiert bereits das Aufrufen einer überschreibbaren Methode in einem Konstruktor als schlechten Stil.
Tags und Links java inheritance