我有一个使用对象标识的令牌类(如equals
中只返回tokenA == tokenB
)。我想在TreeSet
中使用它。这意味着我需要在两个与参考相等兼容的令牌之间进行比较。我不关心具体的实现,只要它与equals
一致并履行合同(按照TreeSet
:"请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。")
注意:这些令牌是在多个线程上创建的,可以在不同的线程上进行比较。
这样做的最佳方法是什么?
我尝试的想法:
System.identityHashCode
- 问题在于无法保证两个不同的对象始终具有不同的哈希码。由于生日悖论,你只需要大约77k令牌才会发生碰撞(假设System.identityHashCode
均匀分布在整个32位范围内,这可能不是真的......)Object.toString
方法的比较器。不幸的是,在引擎盖下,这只是使用哈希码(与上面相同)。AtomicInteger
/ AtomicLong
有点帮助,但它的大小膨胀更多在这里烦人)。System.identityHashCode
和静态消歧图。这有效,但相当复杂。此外,Java默认情况下没有ConcurrentWeakValueHashMultiMap
(不是一口),这意味着我必须引入外部依赖(或者写我自己的 - 可能使用与this类似的东西来执行此操作,或遭受(缓慢)内存泄漏,或使用终结器(呃)。 (而且我不知道是否有人实施了这样的事情......)顺便说一句,我不能解决这个问题并假设唯一对象具有唯一的哈希码。那就是我在做什么,但是在比较器中发出了断言,所以我挖了它,然后,在我的机器上看到以下内容:
import java.util.*;
import java.util.Collections.*;
import java.lang.*;
public class size {
public static void main(String[] args) {
Map<Integer, Integer> soFar = new HashMap<>();
for (int i = 1; i <= 1_000_000; i++) {
TokenA t = new TokenA();
int ihc = System.identityHashCode(t);
if (soFar.containsKey(ihc)) {
System.out.println("Collision: " + ihc +" @ object #" + soFar.get(ihc) + " & " + i);
break;
}
soFar.put(ihc, i);
}
}
}
class TokenA {
}
打印
Collision: 2134400190 @ object #62355 & 105842
所以碰撞确实存在。 那么,有什么建议吗?
答案 0 :(得分:0)
问题tokenA == tokenB
比较身份,tokenA.equals(tokenB)
比较.equals()
中为该类定义的内容,无论身份如何。
因此,两个对象可以.equals()
返回true
而不是相同的对象实例,它们甚至不必具有相同类型或共享超类型。
实现compareTo()
是您要比较的任何对象的属性。您只需编写代码并使其按照您的意愿执行,但compareTo()
可能不您想要的内容。 compareTo()
用于进行比较,如果您有两个事物以<
或>
彼此以某种有意义的方式相互作用,那么Comparable
和Comparator<T>
就不是您想要的。
public boolean equals(Object o)
{
return this == o;
}