Ich weiß, das ist sinnlos: Ich finde es einfach witzig und möchte mehr über die Mechanismen erfahren, die passieren, wenn Sie eine Klasse erstellen, die sich selbst erbt, was zu einem Absturz des Stack-Überlaufs führt. Es ist erstaunlich, dass Java Ihnen erlaubt, ein solches Konstrukt zu erstellen.
Ich rate nur, aber setzt sich die JVM selbst in eine Endlosschleife, um die Klasse aufzulösen, bevor sie instanziiert wird, oder setzt sie tatsächlich mehrere Kopien der Klasse endlos fort?
Ich hätte genauer sein sollen; Ich verwende eine innere Klasse, um von der einschließenden Klasse abzuleiten.
%Vor% Beachten Sie, dass, da Inside
erweitert Outside
ist, es einen impliziten Aufruf von super()
hat, was der Konstruktor von Outside
ist (der wiederum den Konstruktor von Inside
aufruft) ) und so geht es rum.
Der von Ihnen gepostete Code unterscheidet sich konzeptionell nicht vom folgenden Programm :
%Vor%In seiner endgültigen Form hat dieses Problem nichts mit zyklischer Vererbung und inneren Klassen zu tun. Es ist nur eine unendliche Rekursion, die durch ungebundenen rekursiven Konstruktoraufruf verursacht wird. Der gleiche Effekt kann durch das folgende einfache Beispiel gezeigt werden:
%Vor%Beachten Sie, dass dieser Code vollkommen gültig ist, da Java keine Einschränkungen für rekursive Aufrufe anwendet.
In Ihrem Fall ist es aufgrund der Vererbung etwas komplizierter, aber wenn Sie sich daran erinnern, dass der Konstruktor der Unterklasse implizit einen Konstruktor der Oberklasse aufruft, sollte klar sein, dass diese Aufrufe eine unendliche Rekursion bilden.
Das von Ihnen gepostete Beispiel könnte problematisch werden, wenn wir es ein wenig mehr ändern:
%Vor% Aber das hängt nicht wirklich mit der Tatsache zusammen, dass Inside
eine innere Klasse von Outside
ist, sie könnte mit getrennten Top-Level-Klassen identisch passiert sein.
Der Java-Compiler wird nicht in eine Endlosschleife eintreten, wenn er versucht, eine zyklische Vererbungskette einzugeben. Schließlich ist jede Vererbungskette ein schließlich endlicher Graph (und rechnerisch gesehen mit einer sehr kleinen Anzahl von Knoten und Kanten). Genauer gesagt muss das Vererbungsdiagramm von Unterklasse A zu (eventueller) Oberklasse Z eine Linie sein (nicht die anders herum, und der Compiler kann leicht feststellen, ob es eine Linie ist oder nicht.
Es braucht nicht viel für ein Programm, um zu bestimmen, ob solch ein kleiner Graph zyklisch ist oder nicht, oder ob es eine Zeile ist oder nicht, was der Compiler tut. Der Compiler geht also nicht in eine Endlosschleife, und die JVM hat nie mehr genügend Speicherplatz, da 1) weder der Compiler auf der JVM noch 2) die JVM ausgeführt wird (da nichts kompiliert wird und der Compiler niemals aufruft) unter solchen Bedingungen die JVM sowieso.)
Mir sind keine Sprachen bekannt, die solche zyklischen Vererbungsgraphen erlauben (aber ich mache seit elf Jahren nichts anderes als Java, so dass meine Erinnerung an etwas anderes als Java matschig ist). Ich kann außerdem nicht sehen, dass Verwendung eines solchen Konstrukts (in der Modellierung oder im realen Leben). Könnte theoretisch interessant sein.
Bearbeiten
Ok, ich habe deinen Code ausgeführt und in der Tat verursacht es einen Stapelüberlauf. Du hattest Recht. Ich muss sitzen und das wirklich studieren, um zu verstehen, warum der Compiler solch ein Konstrukt erlaubt.
Nice find !!!!
Die Erweiterung von sich selbst erzeugt einen Fehler der zyklischen Vererbung (was java nicht zulässt). Ihr Codebeispiel wird kompiliert und ist gültig.
Wegen Vladimir Ivanovs Beharrlichkeit werde ich meine Bearbeitung reparieren.
Ihr Code löst wegen des Folgenden eine StackOverflowError
aus.
Da Inside
dehnt Outside
aus, ruft Inside
zuerst die Methode super()
implizit auf (da Sie sie nicht selbst aufgerufen haben). Outside()
Konstruktor initialisiert Inside o
und der Zyklus wird erneut ausgeführt, bis der Stapel voll ist und er überläuft (es gibt zu viele Inside
und Outside
im Heap-Stapel).
Hoffe das hilft besonders Vladimir Ivanov.
Tags und Links java inheritance oop