Perché le raccolte Java non memorizzano direttamente i tipi di primitive?

Le raccolte Java memorizzano solo oggetti, non tipi primitivi; tuttavia possiamo memorizzare le classi wrapper.

Perché questo vincolo?

Si trattava di una decisione di progettazione Java, e uno che considera un errore. I contenitori vogliono che Oggetti e primitive non derivino da Object.

Questo è un posto che i progettisti .NET hanno imparato dalla JVM e implementato tipi di valore e generici tali che la boxe è stata eliminata in molti casi. In CLR, i contenitori generici possono memorizzare tipi di valore come parte della struttura del contenitore sottostante.

Java ha optato per aggiungere il supporto generico al 100% nel compilatore senza il supporto di JVM. Essendo JVM quello che è, non supporta un object “non object”. I generici Java ti permettono di fingere che non ci sia un wrapper, ma tu paghi comunque il prezzo della boxe. Questo è IMPORTANTE per alcune classi di programmi.

La boxe è un compromesso tecnico e ritengo che il dettaglio dell’attuazione sfugga al linguaggio. Autoboxing è un buon zucchero sintattico, ma è comunque una penalità per le prestazioni. Se non altro, mi piacerebbe che il compilatore mi avvisasse quando si autoboxes. (Per quanto ne so, potrebbe ora, ho scritto questa risposta nel 2010).

Una buona spiegazione su SO del pugilato: perché alcune lingue richiedono Boxing e Unboxing?

E le critiche ai generici di Java: perché alcuni sostengono che l’implementazione di Java di generici è ctriggers?

Nella difesa di Java, è facile guardare indietro e criticare. La JVM ha resistito alla prova del tempo ed è un buon progetto sotto molti aspetti.

Rende l’implementazione più semplice. Poiché le primitive Java non sono considerate oggetti, è necessario creare una class di raccolta separata per ciascuna di queste primitive (nessun codice modello da condividere).

Puoi farlo, ovviamente, vedi GNU Trove , Apache Commons Primitives o HPPC .

A meno che tu non abbia raccolte veramente grandi, il sovraccarico per i wrapper non è abbastanza importante per le persone a cui prestare attenzione (e quando hai raccolte primitive molto grandi, potresti voler impiegare lo sforzo per cercare di usare / build una struttura dati specializzata per loro ).

È una combinazione di due fatti:

  • I tipi primitivi Java non sono tipi di riferimento (ad es. Un int non è un Object )
  • Java genera generici usando la cancellazione dei tipi dei tipi di riferimento (ad esempio un List È in realtà un List in fase di esecuzione)

Poiché entrambe sono vere, le raccolte Java generiche non possono memorizzare direttamente i tipi primitivi. Per praticità, è stata introdotta la funzione di autoboxing per consentire ai tipi primitivi di essere inseriti automaticamente come tipi di riferimento. Non fare errori su di esso, tuttavia, le collezioni stanno ancora memorizzando i riferimenti agli oggetti a prescindere.

Questo potrebbe essere stato evitato? Forse.

  • Se un int è un Object , non è necessario alcun tipo di scatola.
  • Se i generici non vengono eseguiti utilizzando la cancellazione del tipo, le primitive potrebbero essere state utilizzate per i parametri di tipo.

C’è il concetto di auto-boxing e auto-unboxing. Se si tenta di memorizzare un int in un List il compilatore Java lo convertirà automaticamente in un Integer .

Non è davvero un limite?

Considerare se si desidera creare una raccolta che memorizza i valori primitivi. Come scriveresti una collezione in grado di memorizzare int, o float o char? Molto probabilmente finirai con più raccolte, quindi avrai bisogno di un intlist e una charlist ecc.

Sfruttando la natura orientata agli oggetti di Java quando si scrive una class di raccolta, è ansible memorizzare qualsiasi object in modo tale che sia necessaria una sola class di raccolta. Questa idea, il polimorfismo, è molto potente e semplifica enormemente la progettazione delle librerie.

Penso che potremmo vedere progressi in questo spazio nel JDK possibilmente in Java 10 basato su questo JEP – http://openjdk.java.net/jeps/218 .

Se si desidera evitare le primitive di inscatolamento nelle raccolte oggi, ci sono diverse alternative di terze parti. Oltre alle già citate opzioni di terze parti ci sono anche le collezioni Eclipse , FastUtil e Koloboke .

Un confronto di mappe primitive è stato pubblicato qualche tempo fa con il titolo: Panoramica HashMap di grandi dimensioni: JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove . La libreria GS Collections (Goldman Sachs) è stata migrata su Eclipse Foundation ed ora è Eclipse Collections.

Il motivo principale è la strategia di progettazione java. ++ 1) le raccolte richiedono oggetti per la manipolazione e le primitive non derivano dall’object, quindi questa può essere l’altra ragione. 2) I tipi di dati primitivi Java non sono un tipo di riferimento per es. int non è un object.

Superare:-

abbiamo il concetto di auto-boxing e auto-unboxing. quindi se stai cercando di memorizzare tipi di dati primitivi, il compilatore lo convertirà automaticamente in object di quella class di dati primitivi.