Reflexão da matriz Java: isArray vs. instanceof

177

Existe uma diferença de preferência ou comportamento entre usar:

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

e

if(obj instanceof Object[]) {}

?

David Citron
fonte

Respostas:

203

Na maioria dos casos, você deve usar o instanceofoperador para testar se um objeto é uma matriz.

Geralmente, você testa o tipo de um objeto antes de fazer o downcast para um tipo específico conhecido em tempo de compilação. Por exemplo, talvez você tenha escrito algum código que possa funcionar com a Integer[]ou an int[]. Você deseja proteger seus elencos com 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 ...

No nível da JVM, o instanceofoperador converte em um código de byte "instanceof" específico , que é otimizado na maioria das implementações da JVM.

Em casos mais raros, você pode estar usando a reflexão para percorrer um gráfico de objeto de tipos desconhecidos. Em casos como esse, o isArray()método pode ser útil porque você não conhece o tipo de componente em tempo de compilação; você pode, por exemplo, implementar algum tipo de mecanismo de serialização e ser capaz de passar cada componente da matriz para o mesmo método de serialização, independentemente do tipo.

Existem dois casos especiais: referências nulas e referências a matrizes primitivas.

Uma referência nula causará o instanceofresultado false, enquanto os isArrayarremessos a NullPointerException.

Aplicado a uma matriz primitiva, o instanceofrendimento é feito false, a menos que o tipo de componente no operando à direita corresponda exatamente ao tipo de componente. Por outro lado, isArray()retornará truepara qualquer tipo de componente.

erickson
fonte
7
Sim, mas quanta diferença isso fará? Isso soa como uma micro-otimização para mim.
Michael Myers
2
@Dims Se você está afirmando que obj instanceof int[]produz falsequando atribui um int[]a obj, está enganado.
22613 Erickson
4
Desculpe, eu quis dizer que obj instanceof Object[]produz falsese Object obj = new int[7].
Dims
3
Certo, em Java, os tipos de dados primitivos não são objetos e não se estendem java.lang.Object, o que faz sentido. Mas instanceofainda pode ser usado para testar matrizes primitivas.
22613 Erickson em
4
-1: em geral, uma vez que matrizes primitivas são matrizes, a chamada isArray()deve ser usada. No caso especial não geral de ter apenas matrizes de objetos, instanceoffornece uma alternativa de alto desempenho.
Sam Harwell
33

No último caso, se obj for nulo, você não receberá uma NullPointerException, mas sim uma falsa.

Burkhard
fonte
8

Se objfor do tipo int[]say, isso terá uma matriz, Classmas não será uma instância de Object[]. Então, o que você quer fazer obj? Se você vai lançá-lo, vá com instanceof. Se você vai usar reflexão, use .getClass().isArray().

Tom Hawtin - linha de orientação
fonte
4

getClass().isArray() é significativamente mais lento no Sun Java 5 ou 6 JRE do que na IBM.

Tanto que o uso clazz.getName().charAt(0) == '['é mais rápido no Sun JVM.

Sebastien Tardif
fonte
10
Você tem alguma estatística, um estudo de caso ou outra evidência à qual possa vincular?
David Citron
4

Recentemente, deparei-me com um problema ao atualizar um aplicativo Groovy do JDK 5 para o JDK 6. O uso isArray()falhou no JDK6:

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

Mudando para instanceof Object[]corrigir isso.

dturanski
fonte
Isso não faz sentido. isArrayé um método de Class, não Type, então é claro GenericArrayTypeImplque não tem esse método. E getClassnunca pode retornar um não- Class Type, então você (ou Groovy ??) deve ter feito algo errado para obter isso, como assumir que cada Typeum é a Class.
kaqqao
3

A reflexão da matriz Java é para casos em que você não possui uma instância da Classe disponível para executar "instanceof". Por exemplo, se você estiver escrevendo algum tipo de estrutura de injeção, que injeta valores em uma nova instância de uma classe, como a JPA, então você precisará usar a funcionalidade isArray ().

Eu escrevi sobre isso no início de dezembro. http://blog.adamsbros.org/2010/12/08/java-array-reflection/

Trenton D. Adams
fonte
2

Se você já tiver uma escolha entre uma solução reflexiva e uma não reflexiva, nunca escolha a reflexiva (envolvendo objetos de classe). Não é que seja "Errado" ou algo assim, mas qualquer coisa que envolva reflexão é geralmente menos óbvia e menos clara.

Bill K
fonte
Bem, "instanceof" é um tipo de reflexão (ou, pelo menos, introspecção) também, mas entendo seu ponto de vista.
David Citron
Além disso, geralmente é mais lento.
Mad Physicist
0

Não há diferença de comportamento que eu possa encontrar entre os dois (exceto o caso nulo óbvio). Quanto a qual versão preferir, eu iria com a segunda. É a maneira padrão de fazer isso em Java.

Se isso confunde os leitores do seu código (porque String[] instanceof Object[]é verdade), convém usar o primeiro para ser mais explícito se os revisores de código continuarem perguntando sobre ele.

hazzen
fonte