2012-06-10 8 views
5

Consideriamo due riferimenti di tipo Integer che chiamare il metodo statico valueOf fabbrica come illustrato di seguito: -è ok per confrontare oggetti immutabili in Java utilizzando == invece di uguale

Integer a = Integer.valueOf("10"); 
    Integer b = Integer.valueOf("10"); 

Considerando che Integer è immutabile, è va bene confrontare aeb usando == invece di usare il metodo equals. Sto indovinando che il metodo valueOf si assicura che solo una istanza di Integer con il valore 10 venga creata e un riferimento a questa istanza venga restituito per ogni numero intero creato con un valore 10.

In generale, va bene confrontare due riferimenti di una classe immutabile che vengono creati utilizzando una chiamata allo stesso metodo di factory statica utilizzando == invece di equals?

Modifica: La classe Integer è stata utilizzata solo come esempio. Sono consapevole che tars Intters fino a 127 restituirà true se vengono confrontati usando ==. Quello che ho bisogno di sapere è che quando creo la mia classe immutabile, ad esempio MyImmutable con un metodo create() che assicurerà che non vengano creati duplicati oggetti MyImmutable, sarà ok se confronto 2 riferimenti MyImmutable creati usando il metodo create da usando == invece di eguali.

+0

Si prega di leggere [questo] (http: //www.javabeat.net/qna/13-what-is-difference-between-equals-and- /) –

+2

L'immutabilità implica semplicemente che non possono cambiare. È necessario prestare particolare attenzione con il caching (non 'new') per garantire che vengano restituiti gli stessi valori per gli stessi parametri di input. –

+0

È possibile utilizzare '==' invece di uguali per i tipi in cui gli uguali non sono stati sovrascritti. Dato che questo potrebbe cambiare in futuro, l'uguaglianza è quasi sempre migliore. L'unica volta che direi '==' è migliore è con tipi come 'enum' che potrebbero essere' null' e usare '==' semplifica il codice in questo caso. –

risposta

6

No, non è sicuro in generale. L'operatore == confronta i riferimenti, non i valori.

L'utilizzo di == avviene per numeri interi compresi tra -128 e 127, ma non per gli altri numeri interi. Il codice seguente dimostra che == non sempre funziona:

Integer a = Integer.valueOf(10); 
Integer b = Integer.valueOf(10); 
System.out.println(a == b); 

true 

Integer c = Integer.valueOf(1000); 
Integer d = Integer.valueOf(1000); 
System.out.println(c == d); 

false 

vederlo lavorare on-line: ideone

La spiegazione di questo comportamento sta nella realizzazione di Integer.valueOf:

public static Integer valueOf(int i) { 
    final int offset = 128; 
    if (i >= -128 && i <= 127) { // must cache 
     return IntegerCache.cache[i + offset]; 
    } 
    return new Integer(i); 
} 

source

Non anche che lo standard richiede che gli interi di boxe per piccoli input (da -128 a 127) danno oggetti con riferimenti uguali.

5.1.7 Boxing conversione

Se il valore p essere inscatolato è vero, falso, un byte, un char nel campo \ u0000 a \ u007F, o un int o un numero breve tra - 128 e 127, quindi lascia che r1 e r2 siano i risultati di due conversioni di boxing di p. È sempre il caso che r1 == r2.

Tuttavia lo standard non offre tali garanzie per numeri interi al di fuori di questo intervallo.


In generale, è ok per confrontare due riferimenti di una classe immutabile, che vengono creati utilizzando una chiamata allo stesso metodo factory statici utilizzando == al posto di eguali?

Come illustrato sopra, non funzionerà in generale. Ma se assicuri che due oggetti immutabili con lo stesso valore abbiano sempre lo stesso riferimento, allora sì, potrebbe funzionare.Tuttavia ci sono alcune regole da seguire attentamente:

  • Il costruttore non deve essere pubblico.
  • Ogni oggetto creato tramite il metodo statico deve essere memorizzato nella cache.
  • Ogni volta che ti viene chiesto di creare un oggetto, devi prima controllare la cache per vedere se hai già creato un oggetto con lo stesso valore.
+0

La mia questionis non riguarda la classe Integer. Spero di ricevere una risposta generale. – CKing

+0

Mi dispiace. Ho perso l'ultima parte. Ho effettuato l'accesso tramite la mia galassia S3 e non è la stessa di un desktop/laptop. :) – CKing

+0

Questa è davvero la risposta che stavo cercando. Molte grazie! – CKing

7

== e uguale() è fondamentalmente diverso.

Si consiglia di leggere questo post per maggiori dettagli:

Difference between Equals/equals and == operator?

Non ha nulla a che fare con oggetti immutabili.

+1

Conosco molto bene la differenza tra uguali e ==. Per favore prova a capire la mia domanda prima di dichiarare l'ovvio. – CKing

+1

Ok. Ti darò un esempio dove andrà bene usare == per confrontare. Ad esempio, ho un'applicazione che ha un oggetto Utente. Mi assicuro di istanziare un'istanza per ogni utente, ad es. Quando chiamo per l'utente con l'ID 123, ci sarà sempre un solo oggetto Utente esistente nella mia intera applicazione con l'ID 123. In questo caso, usando == è accettabile confrontare 2 oggetti Utente per vedere se sono lo stesso utente. –

+0

Altrimenti, generalmente non è corretto confrontare 2 oggetti usando == Scusate se ho dichiarato l'ovvio, ma la vostra domanda prima della modifica era una direzione completamente diversa. –

1

Non sono lo stesso oggetto, quindi == non sarà vero. Con gli oggetti, sii sicuro e usa equals().

+2

Tecnicamente, le cache 'valueOf' (di default) da -128 a 127 quindi in questo caso' a == b' sarà vero. Ma sì, sicuramente uso '.equals' comunque. – Kevin

+0

Sto parlando di una classe che garantisce che non vengano creati duplicati. Per favore prova a capire una domanda prima di saltare a una risposta .. – CKing

+1

@bot: la tua domanda originale non affermava che la classe assicurava che non erano stati creati duplicati. Hai modificato la tua domanda dopo che questa risposta è stata pubblicata. –

5

Se il metodo factory restituisce lo stesso oggetto per gli input uguali, è sicuro confrontarli con ==. Ad esempio, String.intern funziona in questo modo. Anche le enumerazioni possono essere confrontate con ==. Ma Integer.valueOf restituisce lo stesso oggetto solo per l'intervallo -128 ... 127 (nella configurazione predefinita).

Integer.valueOf(127) == Integer.valueOf(127) 

ma

Integer.valueOf(128) != Integer.valueOf(128) 

In generale si consiglia di utilizzare il metodo equals per confrontare tutti gli oggetti. L'operatore == potrebbe essere usato per migliorare le prestazioni, quando ci sono pochi valori diversi per l'oggetto. Non consiglierei di usare questo metodo, a meno che tu non sia sicuro al 100% di ciò che stai facendo.

+0

Grazie per aver compreso la domanda piuttosto che aver dichiarato l'ovvio. Quindi la mia classe immutabile, è ok usare == invece di eguali se posso assicurare che nessun duplucato esisterà mai. – CKing

+0

Se il tuo metodo factory funziona correttamente e nessuno farà cose sporche come chiamare costruttori privati ​​tramite la reflection, tutto dovrebbe funzionare. Quindi se hai delle buone ragioni per farlo, vai avanti. – vbezhenar

2

L'immutabilità e l'uguaglianza non hanno necessariamente qualcosa a che fare l'uno con l'altro. == confronta per uguaglianza di riferimento, cioè, confronta se entrambe le variabili puntano alla stessa istanza dell'oggetto. L'uguaglianza significa che entrambi gli oggetti condividono lo stesso valore. Immutabilità ora significa che non è possibile modificare un oggetto dopo la sua costruzione.

Quindi, potresti avere due oggetti immutabili, che rappresentano lo stesso valore (nel senso che sono uguali in modo che a.equals (b) restituisce true) ma che non sono la stessa istanza.

ho un piccolo esempio per voi qui:

 
public class MyPoint { 
    private int x; 
    private int y; 

    public MyPoint(int x, int y) { 
     this.x = x; 
     this.y = y; 
    } 

    public int getX() { 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (!(obj instanceof MyPoint)) 
      return false; 
     MyPoint p = (MyPoint) obj; 
     return this.x == p.x && this.y == p.y; 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     MyPoint p = new MyPoint(2, 2); 
     MyPoint q = new MyPoint(2, 2); 
     MyPoint r = q; 

     System.out.println(p == q); 
     System.out.println(p == r); 
     System.out.println(q == r); 
     System.out.println(p.equals(q)); 
     System.out.println(p.equals(r)); 
     System.out.println(q.equals(r)); 

    } 

}

L'output è: falso falso vero vero vero vero

myPoint è immutabili. Non è possibile modificare i suoi valori/il suo stato dopo che è stato inizializzato. Ma, come puoi vedere, due oggetti di myPoint potrebbero essere uguale a, ma potrebbero non essere la stessa istanza.

Penso che quello che hai in mente sia una specie di modello a zampa di mosca, in cui esiste un solo oggetto per ogni possibile stato dell'oggetto. Flyweight significa anche comunemente che quegli oggetti sono immutabili.

+0

Grazie per il riferimento del peso mosca! – CKing

Problemi correlati