Comment obtenir l’identifiant unique d’un object qui remplace hashCode ()?

Lorsqu’une classe en Java ne remplace pas hashCode () , l’impression d’une instance de cette classe donne un joli numéro unique.

Le Javadoc de Object dit à propos de hashCode () :

Dans la mesure du possible, la méthode hashCode définie par la classe Object renvoie des entiers distincts pour des objects distincts.

Mais quand la classe remplace hashCode () , comment puis-je obtenir son numéro unique?

    System.identityHashCode (yourObject) donnera le code de hachage ‘original’ de votre object comme un entier. L’unicité n’est pas nécessairement garantie. L’implémentation Sun JVM vous donnera une valeur liée à l’adresse mémoire d’origine de cet object, mais c’est un détail d’implémentation et vous ne devriez pas vous y fier.

    EDIT: Réponse modifiée suite au commentaire de Tom ci-dessous re. adresses mémoire et objects en mouvement.

    Le javadoc pour Object spécifie que

    Ceci est généralement implémenté en convertissant l’adresse interne de l’object en un entier, mais cette technique d’implémentation n’est pas requirejse par le langage de programmation JavaTM.

    Si une classe remplace hashCode, cela signifie qu’elle veut générer un identifiant spécifique, qui (on peut l’espérer) aura le bon comportement.

    Vous pouvez utiliser System.identityHashCode pour obtenir cet identifiant pour n’importe quelle classe.

    Peut-être que cette solution rapide et sale fonctionnera?

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

    Cela indique également le nombre d’instances d’une classe en cours d’initialisation.

    hashCode() permet pas de fournir un identifiant unique pour un object. Il digère plutôt l’état de l’object (c.-à-d. Les valeurs des champs membres) en un seul entier. Cette valeur est principalement utilisée par certaines structures de données basées sur le hachage, telles que les cartes et les ensembles, pour stocker et récupérer efficacement des objects.

    Si vous avez besoin d’un identifiant pour vos objects, je vous recommande d’append votre propre méthode au lieu de remplacer le hashCode . Pour cela, vous pouvez créer une interface de base (ou une classe abstraite) comme ci-dessous.

     public interface IdentifiedObject { I getId(); } 

    Exemple d’utilisation:

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

    Pour la génération d’ID, vous pouvez consulter mon article de blog que j’ai essayé d’expliquer comment générer des identifiants uniques.

    Si vous pouvez modifier une classe, vous pouvez déclarer une variable de classe static java.util.concurrent.atomic.AtomicInteger nextInstanceId . (Vous devrez lui donner une valeur initiale de manière évidente.) Puis déclarez une variable d’ int instanceId = nextInstanceId.getAndIncrement() .

    Je suis venu avec cette solution qui fonctionne dans mon cas où j’ai des objects créés sur plusieurs threads et qui sont sérialisables:

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

    Juste pour augmenter les autres réponses sous un angle différent.

    Si vous voulez réutiliser le (s) hashcode (s) de ‘above’ et en dériver de nouveaux en utilisant l’état immuable de votre classe, alors un appel à super fonctionnera. Bien que cela puisse / peut ne pas se produire en cascade jusqu’à Object (c’est-à-dire que certains ancêtres ne peuvent pas appeler super), cela vous permettra de dériver des codes de hachage en les réutilisant.

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

    Il y a une différence entre les retours hashCode () et identityHashCode (). Il est possible que pour deux objects inégaux (testés avec ==) o1, o2 hashCode () puisse être identique. Voir l’exemple ci-dessous comment c’est vrai.

     class SeeDifferences { public static void main(Ssortingng[] args) { Ssortingng s1 = "stackoverflow"; Ssortingng s2 = new Ssortingng("stackoverflow"); Ssortingng s3 = "stackoverflow"; 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"); } } } 

    J’avais le même problème et je n’étais satisfait d’aucune des réponses, car aucun d’entre eux ne garantissait des identifiants uniques.

    Je voulais aussi imprimer des identifiants d’object pour le débogage prévu. Je savais qu’il devait y avoir un moyen de le faire, car dans le débogueur Eclipse, il spécifie des identifiants uniques pour chaque object.

    Je suis venu avec une solution basée sur le fait que l’opérateur “==” pour les objects ne renvoie que true si les deux objects sont en fait la même instance.

     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 ids = new HashMap(); /** Map from assigned IDs to their corresponding objects */ private Map objects = new HashMap(); /**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); } } } 

    Je pense que cela devrait assurer des identifiants uniques tout au long de la vie du programme. Notez toutefois que vous ne souhaitez probablement pas l’utiliser dans une application de production car elle conserve des références à tous les objects pour lesquels vous générez des ID. Cela signifie que tous les objects pour lesquels vous créez un identifiant ne seront jamais collectés.

    Comme je l’utilise à des fins de débogage, je ne suis pas trop préoccupé par la mémoire libérée.

    Vous pouvez modifier cela pour autoriser la suppression d’objects ou la suppression d’objects individuels si la libération de mémoire est un problème.