2015-07-16 8 views
48

Sto cercando di determinare se le seguenti affermazioni sono garantiti per essere vero:Chiamata autoboxing valoreOf()?

((Boolean)true) == Boolean.TRUE 
((Boolean)true) == Boolean.valueOf(true) 
((Integer)1) == Integer.valueOf(1) 

Ho sempre pensato che autoboxing era equivalente a chiamare valueOf() sul tipo corrispondente. Ogni discussion che ho visto su topic sembra essere il mio presupposto per support. Ma tutto quello che ho potuto trovare nella JLS è stata la seguente (§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 true o false (§3.10.3), o un carattere letterale tra '\u0000' e '\u007f' compreso (§3.10.4), poi lasciate a e b tramite i risultati di eventuali due conversioni boxe p. È sempre il caso di a == b.

che descrive il comportamento identico * simile a quella di valueOf(). Ma non sembra esserci alcuna garanzia che venga effettivamente invocato lo valueOf(), il che significa che potrebbe teoricamente essere un'implementazione che mantiene una cache dedicata separata per i valori autoboxed. In tal caso, potrebbe non esserci un'identità di identità tra i valori memorizzati in cache memorizzati nella cache e i valori regolari memorizzati nella cache.

Oracle's autoboxing tutorial afferma materia realisticamente che li.add(i) viene compilato in li.add(Integer.valueOf(i)), dove i è un int. Ma non so se il tutorial debba essere considerato una fonte autorevole.


* è una garanzia leggermente più debole rispetto valueOf(), poiché si riferisce solo ai valori letterali.

+5

@ Jean-FrançoisSavard Questo non è un duplicato di 408661. In effetti l'ho collegato alla mia domanda. So che generalmente si compila a 'valueOf()'; la mia domanda è se la JLS abbia qualche garanzia al riguardo. – shmosel

+0

Interessante domanda teorica. Posso chiederti dove vuoi applicare questo? –

+0

Questo tipo di domanda è difficile (ma non impossibile) per dare una risposta definitiva, perché (tecnicamente parlando) richiede di leggere l'intero JLS back to back e assicurarsi che non ci siano tali garanzie. (Ho [postato una domanda] (http://stackoverflow.com/questions/27566938/could-the-jit-collapse-two-volatile-reads-as-one-in-certain-expressions) con lo stesso problema un po ' fa.) Detto questo, ho cercato l'intero JLS per 'valueOf' e nessuno degli hit era legato alla autoboxing (solo cose su' Enum.valueOf' etc). Secondo me questo lo sistema. – aioobe

risposta

29

ho prima di un pensato alla tua domanda è stata una vittima di What code does the compiler generate for autoboxing?

Tuttavia, dopo il tuo commento su @ElliottFrisch ho capito che era diverso:

So che il compilatore si comporta in quel modo. Sto cercando di capire se tale comportamento è garantito.

Per altri lettori, supporre che "si comporti in questo modo" significhi utilizzare valueOf.

Ricordare che esistono compilatori multipli per Java. Per essere "legali" devono seguire il contratto indicato nello JLS. Pertanto, fintanto che tutte le regole qui sono rispettate, non vi è alcuna garanzia di come l'autoboxing sia implementato internamente.

Ma non vedo alcun motivo per non utilizzare valueOf, in particolare che utilizza i valori memorizzati nella cache ed è il modo consigliato in base a this article di Joseph D. Darcy.

-2

Il tutorial di autoboxing di Oracle afferma in modo pratico che li.add (i) è compilato in li.add (Integer.valueOf (i)), dove i è un int.Ma non so se il tutorial debba essere considerato una fonte autorevole.

Sto eseguendo Oracle Java 1.7.0_72 sembra che usi valueOf. Di seguito è riportato un codice e il codice byte per esso. Il bytecode mostra che sta usando valueOf.

public class AutoBoxing { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     Integer x = 5; 
     int i = x; 
     System.out.println(x.toString()); 
    } 

} 





Compiled from "AutoBoxing.java" 
public class testing.AutoBoxing { 
    public testing.AutoBoxing(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_5 
     1: invokestatic #2     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
     4: astore_1 
     5: aload_1 
     6: invokevirtual #3     // Method java/lang/Integer.intValue:()I 
     9: istore_2 
     10: getstatic  #4     // Field java/lang/System.out:Ljava/io/PrintStream; 
     13: aload_1 
     14: invokevirtual #5     // Method java/lang/Integer.toString:()Ljava/lang/String; 
     17: invokevirtual #6     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     20: return 

Ma non so cosa usi Open JDK. Proveremo.

+3

Come risponde la domanda? –

+2

@ Jean-FrançoisSavard, non ho trovato nessuna frase terminata con punti interrogativi nel post originale. Quindi immaginavo che l'ultima frase suonasse come la domanda per me. Il post è composto da poche asserzioni e scopre e termina con 'Ma non so se il tutorial debba essere considerato una fonte autorevole. '. Quindi per me sembrava la domanda che valeva la pena affrontare. –

+0

@JoseMartinez, la prima frase era la domanda, nonostante la mancanza di un punto interrogativo. Se stavo cercando prove aneddotiche, avrei potuto rispondere alla mia domanda semplicemente eseguendo il mio codice. – shmosel

16

Fino a quando la specifica della lingua non la menziona, non è garantito che l'autoboxing sia equivalente a una chiamata ai metodi statici valueOf. Si tratta di un'implementazione , non inclusa nella specifica di conversione di boxe. Un'implementazione è teoricamente libera di utilizzare un altro meccanismo purché sia ​​conforme alla regola che hai citato dal JLS.

In pratica, ci sono molte segnalazioni di bug Sun JDK (ad esempio JDK-4990346 e JDK-6628737) che implicano chiaramente che quando autoboxing è stato introdotto in Java 5, l'intenzione era avere il compilatore a fare affidamento su valueOf come indicato in JDK-6628737:

I metodi statici di fabbrica Integer.valueOf (int), Long.valueOf (long), ecc. Sono stati introdotti in JDK 5 per javac per implementare il comportamento di caching richiesto dalle specifiche di autoboxing.

Ma questo è solo per javac, non necessariamente tutti i compilatori.

2

Autoboxing è assolutamente implementato utilizzando valueOf() ... in OpenJDK. Se questa è la tua implementazione, continua a leggere ... se no, vai al di sotto.

((Boolean)true) == Boolean.TRUE 
((Boolean)true) == Boolean.valueOf(true) 

documentazione Java afferma che Boolean.valueOf() restituisce sempre Boolean.TRUE o Boolean.FALSE, pertanto i confronti di riferimento in questi casi avranno successo.

((Integer)1) == Integer.valueOf(1) 

Per questo particolare esempio, sotto l'attuazione OpenJDK con le impostazioni predefinite, sarà probabilmente lavoro in virtù del fatto che si scelto un valore < 128 che viene memorizzato nella cache all'avvio (anche se questo può essere sostituito come una linea di comando arg). È può anche funzionare per i valori più grandi se è utilizzato frequentemente abbastanza per essere memorizzato nella cache. A meno che tu non stia lavorando su ipotesi "sicure" sulla cache Integer, non aspettarti che il confronto di riferimento sia un'eguaglianza.

Long, Short, Character e Byte inciso attuare questo caching troppo, ma a differenza di Integer, non è sintonizzabile. Byte funzionerà sempre se si confrontano i riferimenti autobox/valueOf() poiché ovviamente non è possibile uscire dall'intervallo. Float e Double creeranno sempre una nuova istanza.


Ora, in termini puramente generici? See this section of the JLS - si DEVE essere dati pari riferimenti per boolean e qualsiasi int o char nell'intervallo da -128 a 127.Ci sono nessuna garanzia per nient'altro.

Problemi correlati