Domanda

Autoboxing è piuttosto spaventoso. Pur comprendendo pienamente la differenza tra == e .equals non posso non aiuto avere il bug follow l'inferno fuori di me:

    final List<Integer> foo = Arrays.asList(1, 1000);
    final List<Integer> bar = Arrays.asList(1, 1000);
    System.out.println(foo.get(0) == bar.get(0));
    System.out.println(foo.get(1) == bar.get(1));

che stampa

true
false

Perché l'hanno fatto in questo modo? E 'qualcosa a che fare con i numeri interi nella cache, ma se questo è il caso perché non hanno semplicemente memorizza nella cache tutti gli interi utilizzati dal programma? Oppure, perché non fa la JVM sempre auto Unbox di primitiva?

Stampa di falso falso o vero vero modo sarebbe stato meglio.

Modifica

Non sono d'accordo per rottura del vecchio codice. Avendo ritorno foo.get(0) == bar.get(0) vero che già rotto il codice.

Può non può risolvere il problema a livello compilatore sostituendo numeri interi con int nel codice byte (fintanto che non viene mai assegnato null)

È stato utile?

Soluzione

  • Perché lo fanno in questo modo?

Ogni numero intero compreso tra -128 e 127 viene memorizzato nella cache da Java. Lo hanno fatto, presumibilmente, per il miglioramento delle prestazioni. Anche se volevano tornare indietro su questa decisione adesso, è improbabile che lo farebbero. Se qualcuno codice costruito in funzione di questo, il loro codice romperebbe quando è stato tolto. Per la codifica il mio hobby, questo forse non importa, ma per il codice aziendale, le persone si arrabbiano e cause legali accadere.

  • Perché non solo cache di tutti gli interi utilizzati dal programma?

tutti gli interi non può essere memorizzata nella cache, perché le implicazioni di memoria sarebbe enorme.

  • Perché l'JVM sempre auto Unbox di primitiva?

Perché la JVM non può sapere quello che si voleva. Inoltre, questo cambiamento potrebbe facilmente rompere il codice legacy non costruito per gestire questo caso.

Se la JVM per automaticamente unboxing alle primitive sulle chiamate a ==, la questione sarà effettivamente diventare più confusa. Ora è necessario ricordare che == confronta sempre riferimenti a oggetti, a meno che gli oggetti possono essere unboxed. Ciò causerebbe ancora più strana confusione casi proprio come quello che di cui sopra.

Invece di preoccuparsi troppo duro su questo, basta ricordare questa regola, invece:

Mai oggetti confrontare con == a meno che non si intende essere confrontandoli con i loro riferimenti. Se lo fai, non riesco a pensare ad uno scenario in cui ci si esegue in un problema.

Altri suggerimenti

Potete immaginare come prestazioni male sarebbe se ogni Integer portato in testa per l'internamento? non lo fa funzionare anche per new Integer.

Il linguaggio Java (JVM non è un problema) non può sempre automaticamente Unbox perché codice progettato per il pre-1.5 Java dovrebbe funzionare.

Integers nel intervallo di byte sono lo stesso oggetto, perché sono memorizzati nella cache. Integers fuori dell'intervallo di byte non sono. Se tutti i numeri interi dovevano essere memorizzati nella cache, immaginare la memoria richiesta.

E da qui

  

Il risultato di tutta questa magia è che si può in gran parte ignorare la distinzione tra int e Integer, con alcune precisazioni. Un'espressione intera può avere un valore nullo. Se il programma tenta di autounbox nulla, si getterà una NullPointerException. I confronti di identità esegue operatore == di riferimento sulle espressioni intere e confronti di uguaglianza valore su Int espressioni. Infine, ci sono i costi di prestazioni associati con la boxe e unboxing, anche se viene fatto automaticamente

Se si salta autoboxing completamente, è ancora ottenere questo comportamento.

final List<Integer> foo =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false

essere più espliciti, se si desidera un comportamento specifico:

final List<Integer> foo =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false

Questa è una ragione, perché Eclipse ha autoboxing come un avvertimento per impostazione predefinita.

Un sacco di persone hanno problemi con questo problema, anche le persone che i libri di scrittura su Java.

Nel Pro di programmazione Java , meri pollici al di sotto sono stati i autore parla problemi con l'utilizzo interi auto-inscatolato come una chiave in un'IdentityHashMap, usa le chiavi di auto-boxed intero in un WeakHashMap. I valori di esempio che usa sono maggiore di 128, quindi la sua chiamata garbage collection riesce. Se qualcuno dovesse usare il suo esempio e sull'uso di valori più piccolo di 128, però, il suo esempio fallirebbe (a causa della chiave è perma-cache).

Quando si scrive

foo.get(0)

il compilatore non importa quanto si è creato l'elenco. Si guarda solo il tipo di tempo di compilazione della lista foo. Quindi, se questo è un List , si tratterà che come un List , come si dovrebbe fare, e un List 's get () restituisce sempre un numero intero. Se si desidera utilizzare il == allora dovete scrivere

System.out.println(foo.get(0).intValue() == bar.get(0).intValue());

non

System.out.println(foo.get(0) == bar.get(0));

, perché questo ha un significato completamente diverso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top