代码之家  ›  专栏  ›  技术社区  ›  ivan_ivanovich_ivanoff

如何获取覆盖hashcode()的对象的唯一ID?

  •  205
  • ivan_ivanovich_ivanoff  · 技术社区  · 16 年前

    当Java中的类不重写时 哈希德() , 打印此类的实例会提供一个很好的唯一编号。

    object的javadoc说 哈希德() :

    只要合理可行,类对象定义的hashcode方法就不会为不同的对象返回不同的整数。

    但是当类重写时 哈希德() 我怎样才能得到 这是唯一的号码?

    10 回复  |  直到 6 年前
        1
  •  311
  •   joseph    8 年前

    System.identityHashCode(yourObject) 将以整数形式给出对象的“原始”哈希代码。独特性并不一定能保证。Sun JVM实现将为您提供一个与此对象的原始内存地址相关的值,但这是一个实现细节,您不应该依赖它。

    编辑:回答修改后汤姆的评论如下。内存地址和移动对象。

        2
  •  27
  •   Valentin Rocher    11 年前

    对象的javadoc指定

    这通常是通过将对象的内部地址转换为整数来实现的,但是JavaTM编程语言不需要这种实现技术。

    如果一个类重写了hashcode,这意味着它想要生成一个特定的ID,这将(人们可以希望)具有正确的行为。

    你可以使用 System.identityHashCode 任何一个班级都可以拿到这个身份证。

        3
  •  8
  •   John Pang    10 年前

    也许这个快速,肮脏的解决方案会奏效?

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

    这还提供了正在初始化的类的实例数。

        4
  •  7
  •   ovunccetin    10 年前

    hashCode() 方法不用于为对象提供唯一标识符。而是将对象的状态(即成员字段的值)分解为单个整数。该值主要由一些基于哈希的数据结构(如映射和集)使用,以有效地存储和检索对象。

    如果需要对象的标识符,我建议您添加自己的方法,而不是重写 hashCode . 为此,您可以创建如下的基本接口(或抽象类)。

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

    示例用法:

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

    对于ID生成,您可以检查 my blog post 我试图解释一些生成唯一ID的方法。

        5
  •  3
  •   Aaron Mansheim    9 年前

    如果是可以修改的类,则可以声明类变量 static java.util.concurrent.atomic.AtomicInteger nextInstanceId . (您必须以明显的方式给它一个初始值。)然后声明一个实例变量 int instanceId = nextInstanceId.getAndIncrement() .

        6
  •  1
  •   Howard Swope    8 年前

    我提出了这个解决方案,在我的例子中,我在多个线程上创建了对象,这些对象是可序列化的:

    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;
        }
    }
    
        7
  •  0
  •   Glen Best    12 年前

    只是从另一个角度增加其他答案。

    如果要重用“above”中的哈希代码,并使用类的“不可变状态”派生新的哈希代码,则对super的调用将起作用。虽然这可能会/可能不会一直层叠到对象(即某些祖先可能不会调用super),但它将允许您通过重用来派生哈希代码。

    @Override
    public int hashCode() {
        int ancestorHash = super.hashCode();
        // now derive new hash from ancestorHash plus immutable instance vars (id fields)
    }
    
        8
  •  0
  •   Developer Marius Žilėnas    10 年前

    hashcode()和identityhashcode()返回之间存在差异。对于两个不相等(用==)的对象O1,o2 hashcode()可能是相同的。请参阅下面的示例,这是如何实现的。

    class SeeDifferences
    {
        public static void main(String[] args)
        {
            String s1 = "stackoverflow";
            String s2 = new String("stackoverflow");
            String 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");
            }
        }
    }
    
        9
  •  0
  •   NateW    9 年前

    我也有同样的问题,到目前为止我对任何答案都不满意,因为它们都不能保证唯一的ID。

    我还想打印对象ID以便进行调试。我知道一定有某种方法可以做到这一点,因为在Eclipse调试器中,它为每个对象指定了唯一的ID。

    我基于这样一个事实提出了一个解决方案:对象的“==”运算符只在两个对象实际上是同一个实例时返回true。

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

    我认为这应该确保在程序的整个生命周期内具有唯一的ID。但是请注意,您可能不想在生产应用程序中使用它,因为它维护对您为其生成ID的所有对象的引用。这意味着您为其创建ID的任何对象都不会被垃圾收集。

    因为我将它用于调试,所以我不太关心内存是否被释放。

    如果需要释放内存,可以修改此选项以允许清除对象或删除单个对象。

        10
  •  0
  •   Frankie    6 年前
    // looking for that last hex?
    org.joda.DateTime@57110da6
    

    如果你在调查 hashcode Java类型 .toString() 在对象上,基础代码是:

    Integer.toHexString(hashCode())