Klasse Sub
ist eine Unterklasse der Klasse Sup
. Was bedeutet das praktisch? Oder mit anderen Worten, was ist die praktische Bedeutung von "Vererbung"?
Option 1: Der Code von Sup wird virtuell nach Sub kopiert . (wie beim Kopieren und Einfügen, jedoch ohne den in der Unterklasse visuell angezeigten kopierten Code ).
Beispiel: methodA()
ist eine Methode, die ursprünglich in Sup. Sub erweitert Sup und methodA()
wird (virtuell) in Sub kopiert. Jetzt hat Sub eine Methode namens methodA()
. Es ist methodA()
in jeder Codezeile mit Sup identisch, gehört jedoch vollständig zu Sub - und hängt nicht von Sup ab oder ist in irgendeiner Weise mit Sup verwandt.
Option 2: Der Code von Sup wird nicht in Sub kopiert . Es ist immer noch nur in der Superklasse. Auf diesen Code kann jedoch über die Unterklasse zugegriffen und von der Unterklasse verwendet werden.
Beispiel: methodA()
ist eine Methode in Sup. Sub erweitert Sup, so dass jetzt methodA()
über Sub wie folgt zugegriffen werden kann : subInstance.methodA()
. Aber das wird tatsächlich methodA()
in der Oberklasse aufgerufen. Dies bedeutet, dass methodA () im Kontext der Oberklasse arbeitet, selbst wenn sie von der Unterklasse aufgerufen wurde.
Frage: Welche der beiden Optionen funktioniert wirklich? Wenn dies nicht der Fall ist, beschreiben Sie bitte, wie diese Dinge tatsächlich funktionieren.
quelle
Antworten:
Option 2.
Der Bytecode wird zur Laufzeit dynamisch referenziert . Deshalb treten beispielsweise LinkageErrors auf.
Angenommen, Sie kompilieren zwei Klassen:
Ändern und kompilieren Sie nun die übergeordnete Klasse, ohne die untergeordnete Klasse zu ändern oder neu zu kompilieren :
Führen Sie abschließend ein Programm aus, das die untergeordnete Klasse verwendet. Sie erhalten einen NoSuchMethodError :
quelle
Beginnen wir mit zwei einfachen Klassen:
und dann
Kompilieren von Methode A und Betrachten des Bytecodes, den man erhält:
Und Sie können genau dort mit der invokespecial-Methode sehen, dass die Suche nach der Sup-Klasse methodA () durchgeführt wird.
Der aufrufspezifische Opcode hat die folgende Logik:
In diesem Fall gibt es in seiner Klasse keine Instanzmethode mit demselben Namen und Deskriptor, sodass das erste Aufzählungszeichen nicht ausgelöst wird. Die zweite Kugel wird jedoch - es gibt eine Superklasse und sie ruft die Methode A des Super auf.
Der Compiler integriert dies nicht und es gibt keine Kopie der Quelle von Sup in der Klasse.
Die Geschichte ist jedoch noch nicht fertig. Dies ist nur der kompilierte Code. Sobald der Code die JVM erreicht,kann sich HotSpot beteiligen.
Leider weiß ich nicht , dass viel über sie, so dass ich in dieser Angelegenheit Autorität ansprechen wird und gehen Inlining in Java , wo gesagt wird , dass HotSpot können Methoden inline (auch nicht-final - Methoden).
Wenn Sie zu den Dokumenten gehen , wird darauf hingewiesen, dass diese Informationen eingefügt werden können, wenn ein bestimmter Methodenaufruf zu einem Hot Spot wird, anstatt diese Suche jedes Mal durchzuführen. Dadurch wird der Code effektiv von Sup methodA () in Sub methodA () kopiert.
Dies erfolgt zur Laufzeit im Speicher, basierend auf dem Verhalten der Anwendung und den Optimierungen, die zur Beschleunigung der Leistung erforderlich sind.
Wie in HotSpot Internals for OpenJDK angegeben, werden "Methoden häufig inline dargestellt. Statische, private, endgültige und / oder" spezielle "Aufrufe lassen sich leicht einfügen."
Wenn Sie sich mit den Optionen für die JVM
-XX:MaxInlineSize=35
befassen, finden Sie eine Option von (35 ist die Standardeinstellung), die die maximale Anzahl von Bytes darstellt, die inline gesetzt werden können. Ich werde darauf hinweisen, dass Java aus diesem Grund gerne viele kleine Methoden hat - weil sie leicht eingefügt werden können. Diese kleinen Methoden werden schneller , wenn sie mehr genannt werden , weil sie können inlined werden. Und während man mit dieser Zahl spielen und sie größer machen kann, kann dies dazu führen, dass andere Optimierungen weniger effektiv sind. (Verwandte SO-Frage: HotSpot JIT-Inlining-Strategie, die eine Reihe anderer Optionen aufzeigt, um einen Blick auf die Internals von Inlining zu werfen, die HotSpot durchführt).Also nein - der Code wird zur Kompilierungszeit nicht eingefügt. Und ja - der Code könnte sehr gut zur Laufzeit eingefügt werden, wenn Leistungsoptimierungen dies rechtfertigen.
Und alles, was ich über HotSpot-Inlining geschrieben habe, gilt nur für HotSpot JVM, das von Oracle vertrieben wird. Wenn Sie sich die Liste der virtuellen Java-Maschinen von Wikipedia ansehen , gibt es viel mehr als nur HotSpot, und die Art und Weise, wie diese JVMs mit Inlining umgehen, kann völlig anders sein als oben beschrieben. Apache Harmony, Dalvik, ART - dort kann es anders laufen.
quelle
Der Code wird nicht kopiert, es wird über Folgendes zugegriffen:
Compiler können optimieren, wie dies im Speicher dargestellt / ausgeführt wird, aber das ist im Grunde die Struktur
quelle