2009-02-24 9 views
83

Vorrei stampare il "riferimento oggetto" di un oggetto in Java per scopi di debug. I.e. per assicurarsi che l'oggetto sia lo stesso (o diverso) a seconda della situazione.Come si ottiene il "riferimento oggetto" di un oggetto in java quando toString() e hashCode() sono stati sovrascritti?

Il problema è che la classe in questione eredita da un'altra classe, che ha scavalcato sia toString() che hashCode() che di solito mi danno l'id.

Esempio di situazione: Esecuzione di un'applicazione multithreading, in cui I (durante lo sviluppo) desidera verificare se tutti i thread utilizzano o meno la stessa istanza di un oggetto risorsa.

+0

a seconda se si può farlo a tutti ... == è il modo andare ... ma non ho idea di come sia stato realizzato il codice in questione. Ancora una volta hashCode è probabilmente adatto per quello che stai facendo, ma potrebbe rompersi a seconda di come è implementata la libreria. – TofuBeer

+0

È davvero una buona domanda. –

risposta

84

Che cosa hai intenzione di fare con esso (ciò che si vuole fare fa la differenza con quello che sarà necessario chiamare).

hashCode, come definito nelle JavaDocs, dice:

Per quanto è ragionevolmente possibile, il metodo hashCode definito dalla classe Object fa ritorno interi distinti per oggetti distinti. (Questo è in genere implementata convertendo l'indirizzo interno dell'oggetto in un intero, ma questa tecnica implementazione non è richiesto dal linguaggio di programmazione Java ™.)

Quindi, se si utilizza hashCode() per scoprire se si tratta di un oggetto unico nella memoria che non è un buon modo per farlo.

System.identityHashCode esegue le seguenti operazioni:

restituisce lo stesso codice hash per l'oggetto dato come sarebbe restituito dal metodo predefinito hashCode(), se la classe dell'oggetto data la priorità hashCode(). Il codice hash per il riferimento null è zero.

Quale, per quello che stai facendo, suona come quello che vuoi ... ma quello che vuoi fare potrebbe non essere sicuro a seconda di come la libreria è implementata.

+4

Non sto agendo sul valore nel codice. Come pr. la mia domanda modifica, la uso solo per scopi di debug di una certa situazione. Ecco perché sento che la mia risposta è ragionevole, ma ti do un +1 per una risposta perspicace. Le probabilità di – Nicolai

+0

sono che farà sempre quello che vuoi, ma potrebbe rompere su alcune VM. – TofuBeer

+0

Si romperà (vale a dire identityHashCode non sarà necessariamente univoco) su qualsiasi VM ragionevole. identityHashCode non è un I.D. –

44

Ecco come ho risolto:

Integer.toHexString(System.identityHashCode(object)); 
+2

Questo non è effettivamente corretto, dal momento che più oggetti possono restituire la stessa identityHashCode. – Robin

+2

Non è vero che due oggetti (riferimenti) con lo stesso hash dell'identità sono lo stesso oggetto? questo è quello che OP vuole – basszero

+2

No, non è vero. È molto probabile, ma non è garantito poiché la specifica NON definisce l'algoritmo. – Robin

3

Non è possibile eseguire in modo sicuro ciò che si desidera poiché il valore predefinito hashCode() potrebbe non restituire l'indirizzo ed è stato menzionato, sono possibili più oggetti con lo stesso hashCode. L'unico modo per ottenere ciò che si desidera è in realtà sovrascrivere il metodo hashCode() per gli oggetti in questione e garantire che tutti forniscano valori univoci. Se questo è fattibile nella tua situazione è un'altra domanda.

Per la cronologia, ho sperimentato più oggetti con lo stesso hash predefinito in una VM IBM in esecuzione su un server WAS. Avevamo un difetto in cui gli oggetti messi in una cache remota venivano sovrascritti a causa di ciò. Questo mi ha aperto gli occhi a quel punto da quando ho assunto che l'hashcode predefinito fosse anche l'indirizzo di memoria degli oggetti.

2

aggiungere un ID unico per tutte le istanze, cioè

public interface Idable { 
    int id(); 
} 

public class IdGenerator { 
    private static int id = 0; 
    public static synchronized int generate() { return id++; } 
} 

public abstract class AbstractSomething implements Idable { 
    private int id; 
    public AbstractSomething() { 
    this.id = IdGenerator.generate(); 
    } 
    public int id() { return id; } 
} 

estendono da AbstractSomething e Query questa proprietà. Saranno al sicuro all'interno di un singolo VM (supponendo che nessun gioco giochi con i classloader per aggirare la statica).

+0

Probabilmente userò AtomicInteger in questo scenario - ha un throughput più elevato perché la sincronizzazione non è richiesta e utilizza le operazioni native di memoria atomica fornite da 'sun.misc.Unsafe' – RAnders00

8

I doppi uguali == controllano sempre in base all'identità dell'oggetto, indipendentemente dall'implementazione degli oggetti di hashCode o uguale. Ovviamente, assicurati che i riferimenti oggetto che stai confrontando siano volatile (in una JVM 1.5+).

Se davvero si deve avere il risultato Object toString originale (sebbene non sia la soluzione migliore per il proprio caso d'uso di esempio), la libreria di Commons Commons ha un metodo ObjectUtils.identityToString(Object) che farà ciò che si desidera. Dal JavaDoc:

public static java.lang.String identityToString(java.lang.Object object) 

ottiene il toString che sarebbe prodotto da Object se una classe non ha esclusione toString stessa. null restituirà null.

ObjectUtils.identityToString(null)   = null 
ObjectUtils.identityToString("")   = "[email protected]" 
ObjectUtils.identityToString(Boolean.TRUE) = "[email protected]" 
+1

Se si sta utilizzando Java 7, è necessario prendere in considerazione l'utilizzo di [java.util.Objects] (http: // docs. oracle.com/javase/7/docs/api/java/util/Objects.html) – noahlz

+5

Questo codice è basato su 'identityHashCode'. – Brice

0

possiamo semplicemente copiare il codice da tostring di classe di oggetti per ottenere il riferimento della stringa

class Test 
{ 
    public static void main(String args[]) 
    { 
    String a="nikhil";  // it stores in String constant pool 
    String s=new String("nikhil"); //with new stores in heap 
    System.out.println(Integer.toHexString(System.identityHashCode(a))); 
    System.out.println(Integer.toHexString(System.identityHashCode(s))); 
    } 
}