Java-Array-Reflexion: isArray vs. instanceof

177

Gibt es einen Präferenz- oder Verhaltensunterschied zwischen der Verwendung von:

if(obj.getClass().isArray()) {}

und

if(obj instanceof Object[]) {}

?

David Citron
quelle

Antworten:

203

In den meisten Fällen sollten Sie den instanceofOperator verwenden, um zu testen, ob ein Objekt ein Array ist.

Im Allgemeinen testen Sie den Typ eines Objekts, bevor Sie es auf einen bestimmten Typ übertragen, der zur Kompilierungszeit bekannt ist. Zum Beispiel haben Sie vielleicht einen Code geschrieben, der mit einem Integer[]oder einem funktionieren kann int[]. Sie möchten Ihre Casts schützen mit instanceof:

if (obj instanceof Integer[]) {
    Integer[] array = (Integer[]) obj;
    /* Use the boxed array */
} else if (obj instanceof int[]) {
    int[] array = (int[]) obj;
    /* Use the primitive array */
} else ...

Auf JVM-Ebene instanceofübersetzt der Operator in einen bestimmten "Instanz" -Bytecode, der in den meisten JVM-Implementierungen optimiert ist.

In selteneren Fällen verwenden Sie möglicherweise die Reflexion, um einen Objektgraphen unbekannter Typen zu durchlaufen. In solchen Fällen kann die isArray()Methode hilfreich sein, da Sie den Komponententyp zur Kompilierungszeit nicht kennen. Möglicherweise implementieren Sie beispielsweise einen Serialisierungsmechanismus und können jede Komponente des Arrays unabhängig vom Typ an dieselbe Serialisierungsmethode übergeben.

Es gibt zwei Sonderfälle: Nullreferenzen und Verweise auf primitive Arrays.

Eine Nullreferenz führt instanceofzum Ergebnis false, während die isArrayWürfe a NullPointerException.

Auf ein primitives Array angewendet instanceofergibt sich die Ausbeute, falsesofern der Komponententyp im rechten Operanden nicht genau mit dem Komponententyp übereinstimmt. Im Gegensatz dazu isArray()wird truefür jeden Komponententyp zurückgegeben.

erickson
quelle
7
Ja, aber wie viel Unterschied wird es machen? Das klingt für mich nach einer Mikrooptimierung.
Michael Myers
2
@Dims Wenn Sie, die behaupten , obj instanceof int[]Ausbeuten , falsewenn Sie eine zuweisen int[]zu obj, Sie irren sich .
erickson
4
Entschuldigung, ich meinte, das obj instanceof Object[]ergibt falsewenn Object obj = new int[7].
Dims
3
Richtig, in Java sind primitive Datentypen keine Objekte und werden nicht erweitert. Das java.lang.Objectist also sinnvoll. Aber instanceofimmer noch für primitive Arrays zum Testen verwendet werden.
Erickson
4
-1: Da primitive Arrays Arrays sind , isArray()sollte im Allgemeinen der Aufruf verwendet werden. In dem nicht ganz allgemeinen Sonderfall, nur Arrays von Objekten zu haben, instanceofbietet sich eine leistungsstarke Alternative an.
Sam Harwell
33

Im letzteren Fall erhalten Sie, wenn obj null ist, keine NullPointerException, sondern eine false.

Burkhard
quelle
8

Wenn objes vom Typ int[]say ist, dann hat das ein Array, ist Classaber keine Instanz von Object[]. Also , was wollen Sie mit zu tun obj. Wenn Sie es besetzen wollen, gehen Sie mit instanceof. Wenn Sie Reflexion verwenden möchten, verwenden Sie .getClass().isArray().

Tom Hawtin - Tackline
quelle
4

getClass().isArray() ist unter Sun Java 5 oder 6 JRE deutlich langsamer als unter IBM.

So viel, dass die Verwendung clazz.getName().charAt(0) == '['von Sun JVM schneller ist.

Sebastien Tardif
quelle
10
Haben Sie Statistiken, eine Fallstudie oder andere Beweise, auf die Sie verlinken können?
David Citron
4

Ich bin kürzlich auf ein Problem beim Upgrade einer Groovy-Anwendung von JDK 5 auf JDK 6 isArray()gestoßen . Die Verwendung in JDK6 ist fehlgeschlagen:

MissingMethodException:
No signature of sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.isArray() ...

Ändern, um instanceof Object[]dies zu beheben.

dturanski
quelle
Das macht keinen Sinn. isArrayist eine Methode von Class, nicht Type, also GenericArrayTypeImplhat diese Methode natürlich nicht. Und getClasskann niemals ein Nicht- zurückgeben Class Type, also müssen Sie (oder Groovy ??) etwas falsch gemacht haben, um dies zu erreichen, wie die Annahme, dass jeder ein Typeist Class.
Kaqqao
3

Java-Array-Reflektion ist für Fälle vorgesehen, in denen keine Instanz der Klasse verfügbar ist, für die "instanceof" ausgeführt werden kann. Wenn Sie beispielsweise eine Art Injection-Framework schreiben, das Werte in eine neue Instanz einer Klasse einfügt, wie dies JPA tut, müssen Sie die isArray () -Funktionalität verwenden.

Ich habe Anfang Dezember darüber gebloggt. http://blog.adamsbros.org/2010/12/08/java-array-reflection/

Trenton D. Adams
quelle
2

Wenn Sie jemals die Wahl zwischen einer reflektierenden und einer nicht reflektierenden Lösung haben, wählen Sie niemals die reflektierende (mit Klassenobjekten). Es ist nicht so, dass es "falsch" oder so ist, aber alles, was Reflexion beinhaltet, ist im Allgemeinen weniger offensichtlich und weniger klar.

Bill K.
quelle
Ähm, "Instanz von" ist auch eine Art Reflexion (oder zumindest Selbstbeobachtung), aber ich verstehe Ihren Standpunkt.
David Citron
Außerdem ist es im Allgemeinen langsamer.
Mad Physicist
0

Es gibt keinen Unterschied im Verhalten, den ich zwischen den beiden finden kann (außer dem offensichtlichen Nullfall). Welche Version ich bevorzugen möchte, würde ich mit der zweiten gehen. Dies ist die Standardmethode in Java.

Wenn es die Leser Ihres Codes verwirrt (weil String[] instanceof Object[]es wahr ist), möchten Sie möglicherweise den ersten verwenden, um expliziter zu sein, wenn Codeprüfer immer wieder danach fragen.

Hazzen
quelle