Java: Klasse erbt sich selbst

8

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%     
TurtleToes 24.03.2011, 10:47
quelle

8 Antworten

8

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%     
aioobe 24.03.2011, 10:57
quelle
2

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.

    
axtavt 24.03.2011 11:12
quelle
1

Versuchen Sie in einer IDE wie Eclipse, es wird Ihnen nicht erlauben, dies zu tun. dh gibt einen solchen Fehler.

Zyklus erkannt: Der Typ Test kann sich selbst oder einen seiner eigenen Elementtypen nicht erweitern / implementieren

    
GuruKulki 24.03.2011 10:53
quelle
1

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.

    
Paŭlo Ebermann 24.03.2011 11:08
quelle
1

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 !!!!

    
luis.espinal 24.03.2011 11:02
quelle
1

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.

%Vor%

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.

    
Buhake Sindi 24.03.2011 10:56
quelle
0

Sie können die Antwort erhalten mit:

%Vor%

Auf diese Weise wird es aufgelöst, aber nicht instanziiert. So können Sie chack, wenn die Auflösung selbst den Absturz verursacht.

Ich schätze, das hängt von der verwendeten JVM ab.

    
vbence 24.03.2011 10:51
quelle
0

Wenn ich versuche zu kompilieren:

%Vor%

Ich bekomme:

%Vor%

Also lass Java dich nicht so etwas tun. Für Informationen, java version "1.6.0_24"

    
krtek 24.03.2011 10:51
quelle

Tags und Links