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[]) {}

?

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.


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.


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().


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.


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.


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/


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.


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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.