numero metodo generar equal automatico autoincremental autoincrementable java identity hashcode

java - metodo - ¿Cómo obtener el ID único de un objeto que reemplaza a hashCode()?



metodo hash java (9)

Cuando una clase en Java no anula hashCode () , imprimir una instancia de esta clase da un buen número único.

El Javadoc de Object dice acerca de hashCode () :

Por más que sea razonablemente práctico, el método hashCode definido por la clase Object devuelve enteros distintos para objetos distintos.

Pero cuando la clase reemplaza a hashCode () , ¿cómo puedo obtener su número único?


El javadoc para Objeto especifica que

Esto generalmente se implementa convirtiendo 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 JavaTM.

Si una clase anula el código hash, significa que quiere generar un ID específico, que (uno puede esperar) tendrá el comportamiento correcto.

Puede usar System.identityHashCode para obtener ese ID para cualquier clase.


Existe una diferencia entre hashCode () y identityHashCode () devuelve. Es posible que para dos objetos desiguales (probados con ==) o1, o2 hashCode () pueda ser el mismo. Vea el siguiente ejemplo de cómo esto es cierto.

class SeeDifferences { public static void main(String[] args) { String s1 = ""; String s2 = new String(""); String s3 = ""; System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s3.hashCode()); System.out.println(System.identityHashCode(s1)); System.out.println(System.identityHashCode(s2)); System.out.println(System.identityHashCode(s3)); if (s1 == s2) { System.out.println("s1 and s2 equal"); } else { System.out.println("s1 and s2 not equal"); } if (s1 == s3) { System.out.println("s1 and s3 equal"); } else { System.out.println("s1 and s3 not equal"); } } }


Se me ocurrió esta solución que funciona en mi caso donde tengo objetos creados en varios subprocesos y son serializables:

public abstract class ObjBase implements Serializable private static final long serialVersionUID = 1L; private static final AtomicLong atomicRefId = new AtomicLong(); // transient field is not serialized private transient long refId; // default constructor will be called on base class even during deserialization public ObjBase() { refId = atomicRefId.incrementAndGet() } public long getRefId() { return refId; } }


Si es una clase que puede modificar, podría declarar una variable de clase static java.util.concurrent.atomic.AtomicInteger nextInstanceId . (Tendrá que darle un valor inicial de la manera obvia). Luego declare una variable de int instanceId = nextInstanceId.getAndIncrement() .


Solo para aumentar las otras respuestas desde un ángulo diferente.

Si desea reutilizar los códigos hash de ''arriba'' y obtener nuevos usando el estado inmutable de su clase, entonces funcionará una llamada a super. Si bien esto puede / no puede ir en cascada hasta Objeto (es decir, es posible que algunos antepasados ​​no llamen super), le permitirá derivar códigos hash por reutilización.

@Override public int hashCode() { int ancestorHash = super.hashCode(); // now derive new hash from ancestorHash plus immutable instance vars (id fields) }


Tal vez esta solución rápida y sucia funcionará?

public class A { static int UNIQUE_ID = 0; int uid = ++UNIQUE_ID; public int hashCode() { return uid; } }

Esto también da el número de instancia de una clase que se está inicializando.


Tuve el mismo problema y hasta ahora no estaba satisfecho con ninguna de las respuestas, ya que ninguna de ellas garantizaba las ID únicas.

Yo también quería imprimir IDs de objetos para la depuración a propósito. Sabía que debía haber alguna forma de hacerlo, porque en el depurador de Eclipse, especifica identificadores únicos para cada objeto.

Se me ocurrió una solución basada en el hecho de que el operador "==" para objetos solo devuelve verdadero si los dos objetos son en realidad la misma instancia.

import java.util.HashMap; import java.util.Map; /** * Utility for assigning a unique ID to objects and fetching objects given * a specified ID */ public class ObjectIDBank { /**Singleton instance*/ private static ObjectIDBank instance; /**Counting value to ensure unique incrementing IDs*/ private long nextId = 1; /** Map from ObjectEntry to the objects corresponding ID*/ private Map<ObjectEntry, Long> ids = new HashMap<ObjectEntry, Long>(); /** Map from assigned IDs to their corresponding objects */ private Map<Long, Object> objects = new HashMap<Long, Object>(); /**Private constructor to ensure it is only instantiated by the singleton pattern*/ private ObjectIDBank(){} /**Fetches the singleton instance of ObjectIDBank */ public static ObjectIDBank instance() { if(instance == null) instance = new ObjectIDBank(); return instance; } /** Fetches a unique ID for the specified object. If this method is called multiple * times with the same object, it is guaranteed to return the same value. It is also guaranteed * to never return the same value for different object instances (until we run out of IDs that can * be represented by a long of course) * @param obj The object instance for which we want to fetch an ID * @return Non zero unique ID or 0 if obj == null */ public long getId(Object obj) { if(obj == null) return 0; ObjectEntry objEntry = new ObjectEntry(obj); if(!ids.containsKey(objEntry)) { ids.put(objEntry, nextId); objects.put(nextId++, obj); } return ids.get(objEntry); } /** * Fetches the object that has been assigned the specified ID, or null if no object is * assigned the given id * @param id Id of the object * @return The corresponding object or null */ public Object getObject(long id) { return objects.get(id); } /** * Wrapper around an Object used as the key for the ids map. The wrapper is needed to * ensure that the equals method only returns true if the two objects are the same instance * and to ensure that the hash code is always the same for the same instance. */ private class ObjectEntry { private Object obj; /** Instantiates an ObjectEntry wrapper around the specified object*/ public ObjectEntry(Object obj) { this.obj = obj; } /** Returns true if and only if the objects contained in this wrapper and the other * wrapper are the exact same object (same instance, not just equivalent)*/ @Override public boolean equals(Object other) { return obj == ((ObjectEntry)other).obj; } /** * Returns the contained object''s identityHashCode. Note that identityHashCode values * are not guaranteed to be unique from object to object, but the hash code is guaranteed to * not change over time for a given instance of an Object. */ @Override public int hashCode() { return System.identityHashCode(obj); } } }

Creo que esto debería garantizar identificaciones únicas durante toda la vida del programa. Sin embargo, tenga en cuenta que es probable que no desee utilizar esto en una aplicación de producción porque mantiene referencias a todos los objetos para los que genera ID. Esto significa que cualquier objeto para el que cree una ID nunca será recolectado como basura.

Ya que estoy usando esto para propósitos de depuración, no estoy muy preocupado por la liberación de la memoria.

Podría modificar esto para permitir borrar objetos o eliminar objetos individuales si liberar memoria es una preocupación.


System.identityHashCode(yourObject) proporcionará el código hash "original" de yourObject como un entero. La singularidad no está necesariamente garantizada. La implementación de Sun JVM le dará un valor relacionado con la dirección de memoria original para este objeto, pero eso es un detalle de la implementación y no debe confiar en ello.

EDITAR: Respuesta modificada siguiendo el comentario de Tom a continuación. Direcciones de memoria y objetos en movimiento.


hashCode() método hashCode() no es para proporcionar un identificador único para un objeto. Más bien digiere el estado del objeto (es decir, los valores de los campos miembros) en un solo entero. Este valor es utilizado principalmente por algunas estructuras de datos basadas en hash como mapas y conjuntos para almacenar y recuperar objetos de manera efectiva.

Si necesita un identificador para sus objetos, le recomiendo que agregue su propio método en lugar de anular el hashCode . Para este propósito, puede crear una interfaz base (o una clase abstracta) como a continuación.

public interface IdentifiedObject<I> { I getId(); }

Ejemplo de uso:

public class User implements IdentifiedObject<Integer> { private Integer studentId; public User(Integer studentId) { this.studentId = studentId; } @Override public Integer getId() { return studentId; } }

Para la generación de ID, puedes consultar la publicación de mi blog que intenté explicar algunas formas de generar ID únicas.