2009-02-24 40 views
83

Me gustaría imprimir la "referencia de objeto" de un objeto en Java con fines de depuración. Es decir para asegurarse de que el objeto sea el mismo (o diferente) según la situación.¿Cómo se obtiene la "referencia de objeto" de un objeto en java cuando toString() y hashCode() se han anulado?

El problema es que la clase en cuestión hereda de otra clase, que ha anulado tanto aString() como a hashCode() que generalmente me daría el id.

Situación de ejemplo: Ejecutar una aplicación de subprocesos múltiples, donde I (durante el desarrollo) desea comprobar si todos los subprocesos utilizan o no la misma instancia de un objeto de recurso.

+0

dependiendo de si se puede hacerlo en absoluto ... == es el camino para ir ... pero no tengo idea de cómo está estructurado el código en cuestión. Nuevamente, es probable que hashCode esté bien para lo que está haciendo, pero podría romperse dependiendo de cómo se implemente la biblioteca. – TofuBeer

+0

Realmente es una buena pregunta. –

Respuesta

84

¿Qué es exactamente lo que planeas hacer con ella (lo que quiere hacer una diferencia con lo que tendrá que llamar).

hashCode, como se define en las JavaDocs, dice:

Tanto como sea razonablemente práctico, el método hashCode definido por la clase Object Función RETURN números enteros distintos de objetos distintos. (Esto se implementa típicamente mediante la conversión de la dirección interna del objeto en un entero, pero esta técnica de implementación no es requerida por el lenguaje de programación Java ™.)

Así que si usted está utilizando hashCode() para averiguar si se trata de un objeto único en la memoria que no es una buena manera de hacerlo.

System.identityHashCode realiza lo siguiente:

devuelve el mismo código hash para el objeto dado como sería devuelto por el método hashCode() por defecto, si es o no la clase del objeto dado anula hashCode(). El código hash para la referencia nula es cero.

Lo que, para lo que está haciendo, suena como lo que quiere ... pero lo que desea hacer podría no ser seguro dependiendo de cómo se implemente la biblioteca.

+4

No estoy actuando sobre el valor en el código. Como pr. mi edición de pregunta, solo la uso para la depuración de una situación determinada. Es por eso que siento que mi respuesta es razonable, pero le doy un +1 por una respuesta perspicaz. Las probabilidades de – Nicolai

+0

es que siempre hará lo que quiera, pero podría romperse en algunas máquinas virtuales. – TofuBeer

+0

Se romperá (es decir, identityHashCode no será necesariamente único) en cualquier VM razonable. identityHashCode no es un ID. –

44

Esto es cómo lo resolví:

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

Esto no es realmente correcto, ya que varios objetos pueden devolver el mismo identityHashCode. – Robin

+2

¿No es cierto que dos objetos (referencias) con el mismo hash de identidad son el mismo objeto? eso es lo que OP quiere – basszero

+2

No, no es verdad. Es muy probable, pero no se garantiza, ya que la especificación NO define el algoritmo. – Robin

3

No se puede hacer lo que se desea con seguridad ya que el hashCode() predeterminado no puede devolver la dirección, y se ha mencionado, son posibles varios objetos con el mismo hashCode. La única forma de lograr lo que desea es anular el método hashCode() para los objetos en cuestión y garantizar que todos proporcionen valores únicos. Si esto es factible en su situación es otra cuestión.

Para el registro, he experimentado varios objetos con el mismo hashcode predeterminado en una VM de IBM que se ejecuta en un servidor WAS. Tuvimos un defecto por el que los objetos colocados en un caché remoto se sobrescribían. Eso fue una revelación para mí en ese momento ya que asumí que el código hash predeterminado también era la dirección de memoria de los objetos.

2

Añadir un identificador único para todas las instancias, es decir

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; } 
} 

se extienden desde AbstractSomething y Query esta propiedad. Estará a salvo dentro de una única vm (suponiendo que no se juegue con los cargadores de clases para evitar la estática).

+0

Probablemente usaría AtomicInteger en este escenario: tiene una mayor rendimiento porque no se requiere sincronización y utiliza operaciones nativas de memoria atómica proporcionadas por 'sun.misc.Unsafe' – RAnders00

8

El doble es igual a == siempre comprobará en función de la identidad del objeto, independientemente de la implementación de los objetos de hashCode o equals. Por supuesto, asegúrese de que las referencias a los objetos que está comparando son volatile (en una JVM 1.5+).

Si realmente debe tener el resultado original Objeto toString (aunque no es la mejor solución para su ejemplo de uso), la biblioteca Commons Lang tiene un método ObjectUtils.identityToString(Object) que hará lo que desee. Desde el JavaDoc:

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

Obtiene el toString que sería producida por objeto si una clase no lo hizo anulación sí toString. null will return null.

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

Si está utilizando Java 7, entonces debería considerar el uso de [java.util.Objects] (http: // docs. oracle.com/javase/7/docs/api/java/util/Objects.html) – noahlz

+5

Este código se basa en 'identityHashCode'. – Brice

0

podemos simplemente copiar el código de toString de la clase de objeto de obtener la referencia de cuerda

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))); 
    } 
} 
Cuestiones relacionadas