2010-12-31 10 views
7

Ci viene insegnato che l'ArrayList di Java è meno efficiente per i numeri interi, perché la lista contiene effettivamente dei puntatori, mentre una serie di interi contiene gli interi, evitando così allocazioni di memoria e accesso.ArrayList è <Integer> ottimizzato da JDK per funzionare come int []?

La mia domanda è se il compilatore JDK/JIT ottimizza questo tipo di inefficienza di distanza? Ha tutte le informazioni per concludere che queste implementazioni sono funzionalmente equivalenti, quindi potrebbe anche sostituire ArrayList con un'implementazione int-backed sotto il cofano.

+0

@ 01 - totalmente d'accordo sul tag 'premature-optimization' - questa è solo la discussione teorica che tutti amiamo fare a volte. – ripper234

risposta

11

No, non può, perché è possibile memorizzare null in un elenco di array.

EDIT: Oh, e non può anche perché i generici vengono cancellati in fase di compilazione - in fase di esecuzione, il JRE non è in grado di distinguere le liste di array dai loro tipi di elementi. IOW, è peggio di solo null - è possibile memorizzare qualsiasi oggetto in un ArrayList<Integer>.

+0

In teoria, un futuro compilatore/runtime Java potrebbe essere in grado di sbarazzarsi del tipo cast, ma il problema 'null' è un blocco permanente per andare fino a' int [] '. Inoltre, conosco un bel po 'di codice che memorizza i valori nulli negli arraylists, quindi non è qualcosa che potrebbe essere in grado di svanire. –

+1

@Donal Fellows. null è sempre sollevare i problemi in java. In questo caso sarebbe possibile utilizzare il vettore bit per memorizzare la proprietà isNull. Quindi possiamo usare uno più lungo int [] per memorizzare tutte le informazioni da ArrayList sign

+0

Il prossimo problema sarebbe girare * Intero get (int) * in * int get (int) * automaticamente per evitare l'autoboxing su ogni chiamata !. (Eliminando la maggior parte dei vantaggi in termini di prestazioni che sospetto) –

3

Si potrebbe, in teoria, ma non è così. Potrebbe non essere più efficiente a meno che non si possa ottimizzare anche l'auto-boxing.

È possibile invece http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntArrayList.html che esegue il wrapping int [].

+0

Sì, ho familiarità con il trove, questa era più una domanda teorica. +1 comunque. – ripper234

+0

@ ripper234, avrei preferito che supportassero l'elenco almeno. La rilevazione automatica sarebbe l'ideale, ma non hanno ancora avuto l'analisi di fuga di base. : P –

+0

Ma questo non funzionerebbe perché 'int' non è correlato al tipo di' Oggetto'. Mentre sarebbe stato possibile che il sistema generico fosse stato progettato per supportare questo genere di cose, avrebbe comportato un cambiamento molto più grande del sistema del classloader rispetto a quello che gli sviluppatori di linguaggio potrebbero sopportare. Dopotutto, Java è * deliberatamente * meno elaborato di C++. –

-3

Così l'attuazione di tale varietà può essere come questo

 
import java.util.AbstractList; 
import java.util.List; 
import java.util.RandomAccess; 

public class IntArrayList extends AbstractList<Integer> 
implements List<Integer> , RandomAccess /* todo , Cloneable, java.io.Serializable */{ 

    private static final int INT_SIZE_MINUS_ONE = 15; 
    private static final int RIGHT_SHIFT = 4; 

    private int size; 
    private int isNull[]; 
    private int data[]; 

    IntArrayList(int size) { 
     if (size < 0) { 
      throw new RuntimeException("invalid size"); 
     } 
     this.size = size; 
     isNull = new int[(size + INT_SIZE_MINUS_ONE) >>> RIGHT_SHIFT]; 
     data = new int[size]; 
    } 

    private void rangeCheck(int index) { 
     if (index < 0 || index >= size) { 
      throw new IndexOutOfBoundsException(); 
     } 
    } 

    public Integer set(int index, Integer element) { 
     rangeCheck(index); 

     Integer oldValue = get(index); 
     if (element == null) { 
      isNull[index >>> RIGHT_SHIFT] &= ~(1 << (index & INT_SIZE_MINUS_ONE)); 
     } else { 
      isNull[index >>> RIGHT_SHIFT] |= (1 << (index & INT_SIZE_MINUS_ONE)); 
      data[index] = element; 
     } 
     return oldValue; 
    } 

    @Override 
    public Integer get(int index) { 
     rangeCheck(index); 
     if ((isNull[index >>> RIGHT_SHIFT] & (1 << (index & INT_SIZE_MINUS_ONE))) == 0) { 
      return null; 
     } 
     return new Integer(data[index]); 
    } 

    @Override 
    public int size() { 
     return size; 
    } 

    public boolean isEmpty() { 
     return size == 0; 
    } 
} 

Può essere utilizzato ovunque come List<Integer>

Tale tipo di oggetto può essere utile per la conservazione a lungo termine delle informazioni che raramente utilizzato. Ridurrà la frammentazione dell'heap a un costo di maggiore generazione di rifiuti sull'accesso agli elementi.

+0

Davvero perché downvote? Se la mia risposta è completamente errata, per favore, dammi un punto. – sign

+0

Perché non è una risposta alla mia domanda. So come implementare un IntArray efficiente. – ripper234

Problemi correlati