2014-09-10 14 views
7

Ho trovato una cosa piuttosto strana per me mentre lavoravo con Java. Forse è una cosa normale, ma non capisco perché funzioni in questo modo.Java. Perché funziona diversamente con i personaggi inglesi e slavi?

Ho un codice come questo:

Character x = 'B'; 
Object o = x; 
System.out.println(o == 'B'); 

Funziona benissimo e l'uscita è "vera". Poi ho cambiare il inglese B a slavo B (Б):

Character x = 'Б'; 
Object o = x; 
System.out.println(o == 'Б'); 

Ora la produzione è "false". Come mai? A proposito, l'output è ancora "vero" se confronto la variabile x con 'Б' direttamente, ma quando lo faccio attraverso un oggetto funziona in modo diverso.

Qualcuno, per favore, può spiegare questo comportamento?

risposta

8

Senza boxe - utilizzando solo char - starai bene. Allo stesso modo se usi equals invece di ==, staresti bene. Il problema è che stai confrontando i riferimenti per i valori in scatola usando ==, che controlla solo l'identità di riferimento. Stai vedendo una differenza a causa del modo in cui funziona il box automatico. Si può vedere la stessa cosa con Integer:

Object x = 0; 
Object y = 0; 
System.out.println(x == y); // Guaranteed to be true 

Object x = 10000; 
Object y = 10000; 
System.out.println(x == y); // *May* be true 

rappresentazioni in scatola In pratica i valori "piccoli" sono memorizzati nella cache, mentre i valori "più grande" non può.

Da JLS 5.1.7:

Se il valore p essere inscatolato è un numero intero letterale di tipo int tra -128 e 127 compreso (§3.10.1), oppure il booleano letterale vero o falso (§3.10. 3), o un carattere letterale tra '\ u0000' e '\ u007f' incluso (§3.10.4), quindi lascia a e b il risultato di due conversioni di boxing di p. È sempre il caso che a == b.

Idealmente, il valore di boxing di un valore primitivo produce sempre un riferimento identico. In pratica, questo potrebbe non essere fattibile utilizzando le tecniche di implementazione esistenti. La regola sopra è un compromesso pragmatico, che richiede che certi valori comuni siano sempre racchiusi in oggetti indistinguibili. L'implementazione può memorizzarli in cache, pigramente o impazientemente. Per altri valori, la regola non consente alcuna ipotesi sull'identità dei valori inseriti nella parte del programmatore. Ciò consente (ma non richiede) la condivisione di alcuni o tutti questi riferimenti. Si noti che i valori letterali interi di tipo long sono consentiti, ma non richiesti, per essere condivisi.

Ciò garantisce che, nei casi più comuni, il comportamento sarà quello desiderato, senza imporre una penalità di prestazioni eccessive, in particolare su dispositivi di piccole dimensioni. Ad esempio, meno implementazioni a memoria limitata possono memorizzare nella cache tutti i valori char e short, nonché i valori int e long nell'intervallo da -32K a +32K.

La parte di "un carattere letterale tra \u0000 and \ u007f`" garantisce che Boxed caratteri ASCII saranno memorizzate nella cache, ma i caratteri non ASCII non inscatolata.

2

quando fate

Character x = 'B' 

invoca Character.valueOf(C)

2: invokestatic #16     // Method java/lang/Character.valueOf:(C)Ljava/lang/Character; 

che memorizza nella cache

Questo metodo sarà sempre i valori della cache nella gamma '\ u0000' a '\ u007F' , incluso, e può memorizzare nella cache altri valori al di fuori di questo intervallo.

public static Character valueOf(char c) { 
    if(c <= 127) { // must cache 
     return CharacterCache.cache[(int)c]; 
    } 
    return new Character(c); 
} 

Simile

Problemi correlati