Ich weiß, dass es zwei Arten von Castings gibt, die implizite und explizite Castings sind. Ich lese verschiedene Fragen zum StackOverflow wie dies dies und dies , aber ich frage mich immer noch, was kostet das Casting in Java und ist es eine gute Idee, es zu vermeiden? Was ist die beste Vorgehensweise dafür?
Es gibt zwei Arten von Castings:
%Vor% In diesem zweiten Fall gibt es Overhead in der Laufzeit, da die beiden Typen überprüft werden müssen und falls das Casting nicht durchführbar ist, muss die JVM ein ClassCastException
werfen.
Jemand hat gesagt, dass es besser ist, die Anwendung zu profilieren, um sicherzustellen, dass Casting nützlich ist oder nicht.
Typumwandlungen sind normalerweise ein Hinweis darauf, dass Sie über eine alternative Lösung für Ihr Problem nachdenken sollten. Schließlich hilft alles, was zur Kompilierzeit überprüft werden kann, dem Programmierer.
Manchmal sind jedoch Typumwandlungen unvermeidlich und in generischem Code passieren sie oft, ohne dass der Programmierer dies bemerkt. Daher wurden erhebliche Anstrengungen unternommen, um den Typwurf sehr schnell zu machen.
In der Vergangenheit enthielt eine Laufzeittyp-Umwandlung die Möglichkeit, dass die Super-Typ-Hierarchie durchlaufen werden muss, um eine Übereinstimmung zu finden. Heute ist eine Typumwandlung nichts anderes als ein Zahlenvergleich plus ein einfacher Zeigervergleich, wenn nicht optimiert, wenn der Analysator beweisen kann, dass die Besetzung immer erfolgreich ist.
Um Typ-Casting schnell zu machen, kennt jede Klasse ihre Tiefe in der Klassenhierarchie und hat eine Tabelle, die alle Super-Typen enthält. Um eine Klasse zu testen, wird ihre Tiefe verglichen und wenn die Tiefe niedriger ist, kann sie keine kompatible Klasse sein und die Typumwandlung schlägt fehl. Andernfalls muss der Eintrag der Tabelle an der Position, die der Tiefe der Prüfklasse entspricht, genau übereinstimmen, so dass alles getestet werden muss.
Zum Beispiel:
%Vor% Die Klasse Container
hat eine Tiefe von 3 und eine der folgenden Superklassen:
Die Klasse JButton
hat eine Tiefe von 5 und eine der folgenden Superklassen:
Jetzt prüft der Typcast:
JButton
hat eine Tiefe von 5, was ≥ 3
ist, die Tiefe von Container
, damit der Test erfolgreich ist Der dritte Eintrag in den Tabellen ist geprüft und stimmt genau überein:
%Vor%Die Hierarchie wird also nicht mehr durchlaufen und der Typ-Cast-Vorgang ist ziemlich billig.
In diesem zweiten Fall gibt es in der Laufzeit einen Overhead, da die beiden Typen überprüft werden müssen und falls das Casting nicht durchführbar ist, muss JVM eine ClassCastException auslösen.
Nicht unbedingt ist es sehr wahrscheinlich, dass die JIT für einen einfachen Fall in der Lage ist, herauszufinden, dass die Besetzung immer funktioniert und den Check optimieren wird. Running ein Mikrobenchmark bestätigt die Annahme:
%Vor%In komplizierteren Situationen funktioniert die Verzweigungsvorhersage auch zu Ihren Gunsten.
Bottom line, wie immer: messen, nicht raten!
Wenn Sie keine leistungskritische Schleife für einen Server schreiben, sollten Sie nicht darüber nachdenken, was schneller ist. Denken Sie statt dessen, was sauberen, wartbaren Code macht. Und Casting steht fast immer im Spannungsfeld zu diesen Zielen und kann normalerweise durch eine bessere Code-Struktur eliminiert werden.
Um Ihre Fragen zu beantworten. Upcasting kostet normalerweise praktisch nichts (wenn Sie den Referenztyp in eine Elternklasse des Objekts ändern). Die Kenntnis des Referenztyps ist ausreichend, um zu entscheiden, ob das Uptping gültig ist, es ruft nur den Klassenlader auf, um die Vererbungskarte nachzuschlagen. Es ist auch eine Überprüfung, die zur Kompilierzeit durchgeführt werden kann. (Es sei denn, der Referenztyp wurde bereits abgelehnt.)
Das Abwärts-Casting ist langsamer, da die JVM die Referenz nehmen muss, die tatsächliche Objektklasse nachschlagen muss, die viele Typen haben kann (viele Schnittstellen implementieren), und für jede solche Schnittstelle prüft sie dann, ob Sie auf eine Casting-Instanz verweisen Gültiger Typ durch (mehr oder weniger) Uptyping für jeden der (möglicherweise vielen) Referenztypen. Da das Downcasting auf das tatsächliche Objekt verweist, kann es nur zur Laufzeit überprüft werden.
Downcasting ist normalerweise kein Performance-Problem (und ist wahrscheinlich JVM-abhängig), aber ich glaube, dass es möglich sein könnte, dies über eine pathologische Wahl der Vererbungsstruktur zu erreichen. Vor allem in Sprachen, die Mehrfachvererbung zulassen.
Sie finden dieser Link interessant
Vermeide den Wurf wenn möglich. Gegossene Gegenstände sind schwerer zu pflegen und haben daher höhere Kosten - wenn Sie ein Objekt überprüfen müssen, verwenden Sie 'instanceof' (zum Beispiel:
%Vor%Damit prüft die JVM, ob Ihr Objekt ein String ist und gibt true zurück, weil Sie o = s gesetzt haben.
Wenn Sie später in Ihrem Code die Superklasse einer Klasse ändern, funktionieren die Umwandlungen möglicherweise nicht mehr und Sie müssen Ihren Code überarbeiten, während Sie hinter instance einfach die Klasse ändern können, für die sie überprüft werden soll.
// Bitte korrigiere mich, wenn ich irgendetwas falsch mache.
Über die Kosten für das Casting in der Zeit: Wie ich bereits erwähnt habe, kostet es viel Zeit, wenn Sie später Ihren Code ändern oder Superklassen ändern. Runtime-weise, wie Casting getan wird, weil es keine Typ-Sicherheit gibt, dauert es weniger Zeit für eine Überprüfung, dann kostet es für eine Ausnahme aufgrund eines nicht erlaubten Cast-Versuch.