Riflessione dell'array Java: isArray vs. instanceof


177

C'è una preferenza o una differenza di comportamento tra l'utilizzo di:

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

e

if(obj instanceof Object[]) {}

?

Risposte:


203

Nella maggior parte dei casi, è necessario utilizzare l' instanceofoperatore per verificare se un oggetto è un array.

In genere, si verifica il tipo di un oggetto prima di eseguire il downcasting a un tipo particolare noto al momento della compilazione. Ad esempio, forse hai scritto del codice che può funzionare con un Integer[]o un int[]. Vorresti proteggere i tuoi cast 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 ...

A livello di JVM, il instanceof operatore si traduce in uno specifico codice byte "instanceof" , che è ottimizzato nella maggior parte delle implementazioni JVM.

In casi più rari, potresti usare la riflessione per attraversare un grafico a oggetti di tipo sconosciuto. In casi come questo, il isArray()metodo può essere utile perché non si conosce il tipo di componente al momento della compilazione; ad esempio, è possibile implementare una sorta di meccanismo di serializzazione ed essere in grado di passare ciascun componente dell'array allo stesso metodo di serializzazione, indipendentemente dal tipo.

Esistono due casi speciali: riferimenti null e riferimenti ad array primitivi.

Un riferimento nullo causerà instanceofai risultati false, mentre la isArraytiri unNullPointerException .

Applicati a una matrice primitiva, i instanceofrendimenti a falsemeno che il tipo di componente sull'operando di destra non corrisponda esattamente al tipo di componente. Al contrario, isArray()verrà restituito trueper qualsiasi tipo di componente.


7
Sì, ma quanta differenza farà? Mi sembra una micro-ottimizzazione.
Michael Myers

2
@Dims Se stai affermando che i obj instanceof int[]rendimenti falsequando assegni un int[]a obj, ti sbagli.
Erickson,

4
Scusate volevo dire che obj instanceof Object[]cede falsese Object obj = new int[7].
Dimmer

3
Giusto, in Java, i tipi di dati primitivi non sono oggetti e non si estendono java.lang.Object, quindi ha senso. Ma instanceofpuò ancora essere usato per testare array primitivi.
Erickson,

4
-1: In generale, poiché le matrici primitive sono matrici, è isArray()necessario utilizzare la chiamata . Nel caso molto generale non speciale di avere solo matrici di oggetti, instanceofoffre un'alternativa ad alte prestazioni.
Sam Harwell,

33

In quest'ultimo caso, se obj è null non otterrai una NullPointerException ma una falsa.


8

Se objè di tipo int[]dire, allora avrà un array Classma non sarà un'istanza di Object[]. Quindi con cosa vuoi fare obj. Se hai intenzione di lanciarlo, vai con instanceof. Se hai intenzione di usare la riflessione, allora usa .getClass().isArray().


4

getClass().isArray() è significativamente più lento su Sun Java 5 o 6 JRE che su IBM.

Tanto che l'utilizzo clazz.getName().charAt(0) == '['è più veloce su Sun JVM.


10
Hai delle statistiche, un caso di studio o altre prove a cui puoi collegarti?
David Citron,

4

Di recente ho isArray()riscontrato un problema durante l'aggiornamento di un'applicazione Groovy da JDK 5 a JDK 6. Utilizzo non riuscito in JDK6:

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

Cambiando per instanceof Object[]risolvere questo problema.


Questo non ha senso. isArrayè un metodo di Classno Type, quindi ovviamente GenericArrayTypeImplnon ha quel metodo. E getClassnon puoi mai restituire un non- Class Type, quindi tu (o Groovy ??) devi aver fatto qualcosa di sbagliato per ottenerlo, come supporre che ogni Typesia un Class.
Kaqqao,

3

La riflessione dell'array Java è per i casi in cui non si dispone di un'istanza della classe disponibile per eseguire "instanceof". Ad esempio, se stai scrivendo una sorta di framework di iniezione, che inietta valori in una nuova istanza di una classe, come fa JPA, allora devi usare la funzionalità isArray ().

Ho scritto questo blog all'inizio di dicembre. http://blog.adamsbros.org/2010/12/08/java-array-reflection/


2

Se hai mai una scelta tra una soluzione riflettente e una soluzione non riflettente, non scegliere mai quella riflettente (che coinvolge oggetti di classe). Non è che sia "sbagliato" o altro, ma tutto ciò che comporta la riflessione è generalmente meno ovvio e meno chiaro.


Ehm, beh, "instanceof" è anche una specie di riflessione (o, almeno, introspezione), ma capisco.
David Citron,

Inoltre, è generalmente più lento.
Fisico pazzo,

0

Non c'è alcuna differenza nel comportamento che posso trovare tra i due (a parte l'evidente caso nullo). Per quanto riguarda quale versione preferirei, andrei con il secondo. È il modo standard di farlo in Java.

Se confonde i lettori del tuo codice (perché String[] instanceof Object[]è vero), potresti voler usare il primo per essere più esplicito se i revisori del codice continuano a chiederlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.