Reflexión de matriz de Java: isArray vs. instanceof

177

¿Hay alguna preferencia o diferencia de comportamiento entre usar:

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

y

if(obj instanceof Object[]) {}

?

David Citron
fuente

Respuestas:

203

En la mayoría de los casos, debe usar el instanceofoperador para probar si un objeto es una matriz.

En general, prueba el tipo de un objeto antes de convertirlo a un tipo particular que se conoce en tiempo de compilación. Por ejemplo, quizás escribiste algún código que puede funcionar con a Integer[]o an int[]. Desea proteger sus yesos con 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 ...

En el nivel de JVM, el instanceofoperador se traduce en un código de bytes "instancia de" específico , que está optimizado en la mayoría de las implementaciones de JVM.

En casos más raros, es posible que esté utilizando la reflexión para atravesar un gráfico de objetos de tipos desconocidos. En casos como este, el isArray()método puede ser útil porque no conoce el tipo de componente en tiempo de compilación; podría, por ejemplo, implementar algún tipo de mecanismo de serialización y poder pasar cada componente de la matriz al mismo método de serialización, independientemente del tipo.

Hay dos casos especiales: referencias nulas y referencias a matrices primitivas.

Una referencia nula causará el instanceofresultado false, mientras que la isArraylanza a NullPointerException.

Aplicado a una matriz primitiva, los instanceofrendimientos a falsemenos que el tipo de componente en el operando de la derecha coincida exactamente con el tipo de componente. Por el contrario, isArray()volverá truepara cualquier tipo de componente.

erickson
fuente
77
Sí, pero ¿cuánta diferencia va a hacer? Eso me parece una microoptimización.
Michael Myers
2
@Dims Si está afirmando que obj instanceof int[]cede falsecuando asigna un int[]a obj, está equivocado.
erickson
44
Lo siento, quise decir que obj instanceof Object[]produce falsesi Object obj = new int[7].
Atenúa
3
Correcto, en Java, los tipos de datos primitivos no son objetos y no se extienden java.lang.Object, por lo que tiene sentido. Pero instanceofaún se puede usar para probar matrices primitivas.
erickson
44
-1: en general, dado que las matrices primitivas son matrices, se isArray()debe utilizar la llamada a las matrices . En el caso especial no muy general de tener solo matrices de objetos, instanceofproporciona una alternativa de alto rendimiento.
Sam Harwell
33

En el último caso, si obj es nulo, no obtendrá una NullPointerException sino una falsa.

Burkhard
fuente
8

Si objes de tipo int[]say, entonces tendrá una matriz Classpero no será una instancia de Object[]. Entonces, ¿qué quieres hacer obj? Si vas a lanzarlo, ve con instanceof. Si vas a usar la reflexión, entonces úsala .getClass().isArray().

Tom Hawtin - tackline
fuente
4

getClass().isArray() es significativamente más lento en Sun Java 5 o 6 JRE que en IBM.

Tanto que el uso clazz.getName().charAt(0) == '['es más rápido en Sun JVM.

Sebastien Tardif
fuente
10
¿Tiene alguna estadística, un estudio de caso u otra evidencia que pueda vincular?
David Citron el
4

Recientemente tuve un problema al actualizar una aplicación Groovy de JDK 5 a JDK 6. El uso isArray()falló en JDK6:

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

Cambiando a instanceof Object[]arreglado esto.

dturanski
fuente
Esto no tiene sentido. isArrayes un método de Class, no Type, así que por supuesto GenericArrayTypeImplno tiene ese método. Y getClassnunca puede devolver un non- Class Type, por lo que usted (o Groovy ??) debe haber hecho algo mal para obtener esto, como asumir que cada uno Typees un Class.
kaqqao
3

La reflexión de matriz de Java es para casos en los que no tiene una instancia de la Clase disponible para hacer "instanceof". Por ejemplo, si está escribiendo algún tipo de marco de inyección, que inyecta valores en una nueva instancia de una clase, como JPA, entonces necesita usar la funcionalidad isArray ().

Hice un blog sobre esto a principios de diciembre. http://blog.adamsbros.org/2010/12/08/java-array-reflection/

Trenton D. Adams
fuente
2

Si alguna vez tiene la opción de elegir entre una solución reflectante y una no reflectante, nunca elija la reflectante (que involucra objetos de clase). No es que sea "incorrecto" ni nada, pero cualquier cosa que implique reflexión es generalmente menos obvia y menos clara.

Bill K
fuente
Er, bueno, "instanceof" es un tipo de reflexión (o, al menos, introspección) también, pero entiendo tu punto.
David Citron
Además, generalmente es más lento.
Físico loco
0

No hay diferencia en el comportamiento que pueda encontrar entre los dos (aparte del obvio caso nulo). En cuanto a qué versión preferiría, iría con la segunda. Es la forma estándar de hacer esto en Java.

Si confunde a los lectores de su código (porque String[] instanceof Object[]es cierto), es posible que desee usar el primero para ser más explícito si los revisores de código siguen preguntando al respecto.

hazzen
fuente