Welche der folgenden Möglichkeiten ist besser?
a instanceof B
oder
B.class.isAssignableFrom(a.getClass())
Der einzige Unterschied, den ich kenne, ist, wenn 'a' null ist, gibt der erste false zurück, während der zweite eine Ausnahme auslöst. Geben sie sonst immer das gleiche Ergebnis?
java
instanceof
reflection
Megamug
quelle
quelle
Antworten:
Bei der Verwendung
instanceof
müssen Sie die Klasse vonB
zur Kompilierungszeit kennen. Bei der VerwendungisAssignableFrom()
kann es dynamisch sein und sich zur Laufzeit ändern.quelle
a instanceof Bref.getClass()
. Wie kann dies die akzeptierte Antwort mit so wenig Erklärung sein (oder deren Fehlen)?a instanceof Bref
nichta instanceof Bref.class
. Das zweite Argument für den Operator instanceof ist ein Klassenname, kein Ausdruck, der in eine Klassenobjektinstanz aufgelöst wird.B.class.isAssignableFrom(a.getClass())
B bekannt unda instanceof B
besser. Recht?instanceof
kann nur mit Referenztypen verwendet werden, nicht mit primitiven Typen.isAssignableFrom()
kann mit allen Klassenobjekten verwendet werden:Sehen http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
quelle
In Bezug auf die Leistung sprechen:
TL; DR
Verwenden Sie isInstance oder instanceof mit ähnlicher Leistung. isAssignableFrom ist etwas langsamer.
Sortiert nach Leistung:
Basierend auf einem Benchmark von 2000 Iterationen unter JAVA 8 Windows x64 mit 20 Aufwärmiterationen.
In der Theorie
Mit einem weichen Bytecode-Viewer können wir jeden Operator in Bytecode übersetzen.
Im Zusammenhang mit:
JAVA:
Bytecode:
JAVA:
Bytecode:
JAVA:
Bytecode:
Wenn wir messen, wie viele Bytecode-Anweisungen von jedem Operator verwendet werden, können wir erwarten, dass instanceof und isInstance schneller sind als isAssignableFrom . Die tatsächliche Leistung wird jedoch NICHT durch den Bytecode bestimmt, sondern durch den Maschinencode (der plattformabhängig ist). Lassen Sie uns für jeden Operator einen Mikro-Benchmark durchführen.
Der Benchmark
Gutschrift: Wie von @ aleksandr-dubinsky empfohlen und danke an @yura für die Bereitstellung des Basiscodes, hier ein JMH- Benchmark (siehe diese Tuning-Anleitung ):
Hat die folgenden Ergebnisse geliefert (Punktzahl ist eine Anzahl von Operationen in einer Zeiteinheit . Je höher die Punktzahl, desto besser):
Warnung
instanceof
der Kontext Ihres Codes möglicherweise einfacher optimiert werden alsisInstance
beispielsweise ...Nehmen Sie als Beispiel die folgende Schleife:
Dank der JIT wird der Code irgendwann optimiert und wir erhalten:
Hinweis
Ursprünglich hat dieser Beitrag einen eigenen Benchmark mit einer for- Schleife in JAVA durchgeführt, was zu unzuverlässigen Ergebnissen führte, da einige Optimierungen wie Just In Time die Schleife beseitigen können. Daher wurde hauptsächlich gemessen, wie lange der JIT-Compiler für die Optimierung der Schleife benötigt hat: Weitere Informationen finden Sie unter Leistungstest unabhängig von der Anzahl der Iterationen
Verwandte Fragen
quelle
instanceof
ist ein Bytecode, der im Wesentlichen dieselbe Logik verwendet wiecheckcast
(der Bytecode hinter dem Casting). Es ist von Natur aus schneller als die anderen Optionen, unabhängig vom Grad der JITC-Optimierung.isAssignableFrom()
ist dynamisch.Ein direkteres Äquivalent zu
a instanceof B
istDies funktioniert (false zurück) , wenn
a
istnull
auch.quelle
Abgesehen von den oben erwähnten grundlegenden Unterschieden gibt es in der Klasse einen subtilen Kernunterschied zwischen der Instanz des Operators und der Methode isAssignableFrom.
Lesen Sie
instanceof
als "Ist dies (der linke Teil) die Instanz dieser oder einer Unterklasse davon (der rechte Teil)" und lesen Siex.getClass().isAssignableFrom(Y.class)
als "Kann ich schreibenX x = new Y()
". Mit anderen Worten, die Instanz des Operators prüft, ob das linke Objekt dasselbe oder eine Unterklasse der rechten Klasse ist, währendisAssignableFrom
prüft, ob wir der Referenz der Klasse, für die die Methode aufgerufen wird, ein Objekt der Parameterklasse (von) zuweisen können.Beachten Sie, dass beide die tatsächliche Instanz und nicht den Referenztyp berücksichtigen.
Betrachten Sie ein Beispiel für 3 Klassen A, B und C, wobei C B und B A erweitert.
quelle
b instanceof A
ist äquivalent zuA.class.isAssignableFrom(b.getClass())
(wie das OP bemerkt hat). Ihr Beispiel ist richtig, aber irrelevant.new Y()
möglicherweise nicht legal ist, wennY
es abstrakt ist oder keinen öffentlichen Standardkonstruktor enthält, können Sie sagen, dassX x = (Y)null
es genau dann legal ist, wennx.getClass().isAssignableFrom(Y.class)
es wahr ist.Es gibt noch einen weiteren Unterschied:
Die Nullinstanz von X ist
false
egal, was X istnull.getClass (). isAssignableFrom (X) löst eine NullPointerException aus
quelle
null instanceof X
(wobei X eine zur Kompilierungszeit bekannte Klasse ist) wird immer zurückgegebenfalse
.X.class.isAssignableFrom(null.getClass())
sollte es nicht? Aber ja, das AufrufengetClass()
einer Nullreferenz führt zu NPE.getClass()
sollte es überhaupt nicht verwendet werdenisAssignableFrom
- die Operation ist für die Situation gedacht, in der keine Objekte vorhanden sind. Wenn Sie den Objektverweis habena
, verwendena instanceof SomeClass
(wenn Sie tun die Art kennenSomeClass
) odersomeObject.getClass().isInstance(a)
(wenn Sie nicht die Art von wissensomeObject
).Es gibt noch einen weiteren Unterschied. Wenn der Typ (Klasse), gegen den getestet werden soll, dynamisch ist, z. B. als Methodenparameter übergeben, wird die Instanz ihn nicht für Sie schneiden.
aber du kannst tun:
Hoppla, ich sehe, dass diese Antwort bereits behandelt wird. Vielleicht ist dieses Beispiel für jemanden hilfreich.
quelle
this
) haben,clazz.isInstance(this)
ist es in Ihrem Beispiel besser.Dieser Thread gab mir einen Einblick in die
instanceof
UnterschiedeisAssignableFrom
, also dachte ich, ich würde etwas von mir teilen.Ich habe festgestellt, dass die Verwendung
isAssignableFrom
die einzige (wahrscheinlich nicht die einzige, aber möglicherweise die einfachste) Möglichkeit ist, sich selbst zu fragen, ob eine Referenz einer Klasse Instanzen einer anderen annehmen kann, wenn man Instanzen keiner Klasse hat, um den Vergleich durchzuführen.Daher fand ich es nicht gut, den
instanceof
Operator zum Vergleichen der Zuweisbarkeit zu verwenden, wenn ich nur Klassen hatte, es sei denn, ich wollte eine Instanz aus einer der Klassen erstellen. Ich dachte, das wäre schlampig.quelle
instanceof kann auch nicht mit primitiven oder generischen Typen verwendet werden. Wie im folgenden Code:
Der Fehler lautet: Es kann keine Instanz der Prüfung für den Typparameter T durchgeführt werden. Verwenden Sie stattdessen das Löschobjekt, da zur Laufzeit weitere allgemeine Typinformationen gelöscht werden.
Kompiliert nicht, da beim Löschen des Typs die Laufzeitreferenz entfernt wird. Der folgende Code wird jedoch kompiliert:
quelle
Betrachten Sie die folgende Situation. Angenommen, Sie möchten überprüfen, ob Typ A eine Superklasse des Typs obj ist, dann können Sie auch gehen
... A.class.isAssignableFrom (obj.getClass ()) ...
ODER
... obj Instanz von A ...
Für die isAssignableFrom-Lösung muss jedoch der Typ des Objekts hier sichtbar sein. Wenn dies nicht der Fall ist (z. B. könnte der Typ von obj einer privaten inneren Klasse angehören), ist diese Option deaktiviert. Die Instanz der Lösung würde jedoch immer funktionieren.
quelle
obj
in diesem Beispiel) eines beliebigen Typs haben , können Sie die öffentlichegetClass()
Methode aufrufen , um die Reflektionsmetadaten für die implementierende Klasse abzurufen. Dies gilt auch dann, wenn dieser implementierende Klassentyp zur Kompilierungszeit an diesem Speicherort rechtlich nicht sichtbar wäre. Es ist OK zur Laufzeit , da für Sie haltenobj
Referenz, einige Codepfad , die letztlich tat müssen die Klasse legalen Zugang erstellt ein und gab (durchgesickert?) Es Ihnen.Der obige Pseudocode ist eine Definition von, wenn Referenzen des Typs / der Klasse A aus Referenzen des Typs / der Klasse B zuweisbar sind. Es handelt sich um eine rekursive Definition. Für einige mag es hilfreich sein, für andere mag es verwirrend sein. Ich füge es hinzu, falls jemand es nützlich finden sollte. Dies ist nur ein Versuch, mein Verständnis zu erfassen, es ist nicht die offizielle Definition. Es wird in einer bestimmten Java VM-Implementierung verwendet und funktioniert für viele Beispielprogramme. Daher kann ich nicht garantieren, dass es alle Aspekte von isAssignableFrom erfasst, aber es ist nicht vollständig deaktiviert.
quelle
Apropos Leistung "2" (mit JMH):
Es gibt:
Damit wir schließen können: Instanz von so schnell wie isInstance () und isAssignableFrom () nicht weit entfernt (+ 0,9% Ausführungszeit). Also kein wirklicher Unterschied, was auch immer Sie wählen
quelle
Wie wäre es mit einigen Beispielen, um es in Aktion zu zeigen ...
quelle
Einige Tests, die wir in unserem Team durchgeführt haben, zeigen, dass dies
A.class.isAssignableFrom(B.getClass())
schneller funktioniert alsB instanceof A
. Dies kann sehr nützlich sein, wenn Sie dies bei einer großen Anzahl von Elementen überprüfen müssen.quelle
instanceof
, glaube ich, dass Sie ernsthafte Designprobleme haben ...