如何在Java中为每个对象获取唯一的ID?

21

我创建了一个向量集,以避免使用迭代器分配等方式导致垃圾回收问题。 (每次遍历 HashSet 的 values 或 keys 时,都需要为 set 引用和 set 迭代器获取新的/释放空闲的内存)

无论如何,据说 Object.hashCode() 方法是对象的唯一标识符。(64位版本可能会失败?)

但无论如何,它都可以被覆盖,因此不能保证独一无二,也不保证每个对象实例的唯一性。

如果我想创建一个“ObjectSet”,如何为每个对象实例获取保证唯一的 ID?

我刚找到了这个答案:

如何获取覆盖 hashCode() 方法的对象的唯一 ID?


1
问题不够清晰。您到底想要实现什么,为什么每个对象都需要一个唯一的ID? - Paolo
1
你所要做的事情描述得非常模糊。你能提供更多信息吗?也许有更好的方法来实现你的大目标。 - Jon Skeet
我看到了这个回答/问题,它回答了我想要的内容。https://dev59.com/63NA5IYBdhLWcg3wkuzO - peterk
@BjörnPollex 对,我找到了重复项 - 它没有出现在我的初始搜索结果中。 - peterk
1
@peterk:是的,我知道。你有阅读IdentityHashMap的文档吗? - Jon Skeet
显示剩余4条评论
4个回答

45

最简单的解决方案是向对象添加一个字段。这是最快速和最有效的解决方案,并避免了任何对象无法清理的问题。

abstract Ided {
    static final AtomicLong NEXT_ID = new AtomicLong(0);
    final long id = NEXT_ID.getAndIncrement();

    public long getId() {
         return id;
    }
}
如果您不能修改类,您可以使用类似于@glowcoder删除的解决方案中的IdentityHashMap。
private static final Map<Object, Long> registry = new IdentityHashMap<Object, Long>();
private static long nextId = 0;

public static long idFor(Object o) {
    Long l = registry.get(o);
    if (l == null)
        registry.put(o, l = nextId++);
    return l;
}

public static void remove(Object o) {
    registry.remove(o);
}

上面的代码在向对象添加字段时,能否保证在同时创建多个线程的情况下每个实例都有唯一的ID? - Geek
1
如果你使用AtomicLong,它就会起作用。 - Peter Lawrey

9
不,这不是hashCode()的工作方式。返回的值不一定是唯一的。确切的契约在文档中有详细说明。
此外,

Object.hashCode()方法据说是每个对象的唯一标识符

这并不正确。引用文档的说法:

尽可能地,由类 Object 定义的 hashCode 方法确实为不同的对象返回不同的整数。


我知道 - 所以我才问这个问题。 - peterk

7
如果你确实需要并且理解其后果,java.lang.System.identityHashCode(obj); 可以为你执行此操作。它可以获取身份哈希码,即使提供哈希码的方法已被覆盖。请注意,此方法仅在必要时使用。

20
即使这个信息已经有几个月了,也应该注意到 System.identityHashCode(Object) 不需要为不同的对象生成不同的哈希码(正如其他答案和评论中已经说明的那样)! - siegi
1
在此提供的解决方案中(附有一些说明和细节):https://dev59.com/63NA5IYBdhLWcg3wkuzO - Benj
identityHashCode() 方法返回 Object 类中定义的 hashCode() 方法的结果。在该方法的 javadoc 中,它声明:“尽可能合理地说,Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(通常通过将对象的内部地址转换为整数来实现此目的,但这种实现技术并非 JavaTM 编程语言所必需的。)” - Roberto Attias
不幸的是,这有点模糊。在64位机器上,虚拟地址空间可能比int更大,因此,尽管不太可能,但两个对象具有相同的值是有可能的。 - Roberto Attias
我刚刚遇到了这个问题,或者说我的一个用户遇到了。调用identityHashCode()函数对几百万个对象进行操作,发现大约有8个对象具有重复的哈希码。 - Michael Kay

2
尝试超越Java GC听起来对我来说像是过早优化。
GC已经调整好了处理小型短寿命对象的能力。如果您在GC方面遇到性能问题,您应该帮助GC,而不是重新实现它(在我看来)。

2
如果有一个实时确定性GC作为通用Java VM的插件可用,我会很喜欢。在每个60hz模拟循环的帧中,我可以保证GC将消耗不超过2毫秒。减少分配和释放可以减少周期性GC停顿的数量。 - peterk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接