Impatto sulle prestazioni di autoboxing
-
26-09-2019 - |
Domanda
Di solito il compilatore genera codice per eseguire boxe e unboxing. Ma cosa fa il compilatore, se non sono necessari i valori in scatola? È il (Oracle standard) compilatore abbastanza intelligente per ottimizzare via?
Date un'occhiata a questo metodo:
public static void requireInRange(int index, Object[] array) {
if(index < 0 || index >= array.length)
throw new IndexOutOfBoundsException();
}
L'informazione rilevante solo il array.length
, quindi sarebbe inutile scatola ogni valore di un array per esempio. Come in questo codice:
int[] anArray = {3, 4, 2};
requireInRange(3, anArray);
Sarà il compilatore in realtà Inserisci Codice per la boxe ogni valore della matrice?
Soluzione
Non c'è autoboxing nel codice. In effetti, data:
public static void requireInRange(int index, Object[] array) {
...
}
int[] anArray = {3, 4, 2};
requireInRange(3, anArray); // DOES NOT COMPILE!!!
Mentre un int
può essere autoboxed a un Integer
, un int[]
non get autoboxed a Integer[]
da Java. È possibile scrivere funzioni di libreria per fare questo, ma la lingua non sarà facilitare questa conversione.
Questo è infatti la fonte di molti confusione riguardo esempio Arrays.asList(anIntArray)
essere "rotto", perché invece di restituire un List<Integer>
, ciò che viene restituito è in effetti un List<int[]>
un elemento.
Ma per quanto riguarda le prestazioni ???
Una citazione da Java Language Guide / Autoboxing :
Non è opportuno utilizzare autoboxing e unboxing per il calcolo scientifico, o altro codice numerico prestazioni sensibili. Un
Integer
non è un sostituto per unint
; autoboxing e sfocatura unboxing la distinzione tra tipi primitivi e tipi di riferimento, ma non eliminarlo.
In breve, quando autoboxing accade, performance prende sicuramente un po 'di un colpo. Certe cose contribuire ad alleviare questo, ad esempio, il meccanismo di cache incorporato in questi tipi. Questo è il motivo per cui si ottiene la seguente:
System.out.println(
((Integer) 0) == ((Integer) 0)
);
// true
System.out.println(
((Integer) 10000) == ((Integer) 10000)
);
// false (implementation-specific)
Quello che è successo è che quando 0
è automaticamente in scatola, senza nuovo istanza Integer
è effettivamente creato: valori in certo intervallo è Copia cache per scopi autoboxing, per aiutare le prestazioni. 10000
nella maggior parte implementazione probabilmente cade fuori di questo intervallo, ma alcune implementazioni JVM fare permettono di specificare l'intervallo di cache, se necessario.
Ma voglio solo per ottenere la lunghezza dell'array !!!
Ci sono molti modi per facilitare il vostro requireInRange
per lavorare con qualsiasi tipo di array. Purtroppo lavorare con serie di Java di primitive spesso significa un sacco di ripetizione. Questo significa fornire sovraccarichi per int[]
, boolean[]
, byte[]
, Object[]
, ecc separatamente.
Una soluzione più concisa è quello di utilizzare la riflessione, ma questo ha i suoi vantaggi e svantaggi. In generale, la riflessione non dovrebbe essere la soluzione preferita per la maggior parte degli scenari.
Detto questo, java.lang.reflect.Array
ha un int getLength(Object array)
static
metodo che può restituire la lunghezza del array QUALSIASI. Non è typesafe (come la maggior parte meccanismo di riflessione sono); passando un non-matrice compilazioni, ma getta IllegalArgumentException
in fase di esecuzione.
Domande correlate
- Gestione codice altamente ripetitivo e la documentazione in Java - ( "ispirato" da
java.util.Arrays
)
Altri suggerimenti
Sarà codice del compilatore in realtà inserto per la boxe ogni valore della matrice?
Il compilatore rifiuterà il codice perché un int[]
non può essere passato in un metodo che accetta un parametro Object[]
.
Autoboxing avviene solo per i singoli valori primitivi, mai per intero array.
In caso di dubbio, si può assumere il compilatore non ottimizzare il codice. In generale si fa una traduzione letterale del codice.
Inoltre, in caso di dubbio youc un assumere la JVM fa un ottimo lavoro di ottimizzazione del codice in fase di esecuzione. Non vorrei pensare che fa alcuna differenza se non si ha una buona ragione (come profiler) a sospettare è un problema.