注意:虽然列表允许将自己包含为元素,但建议极其谨慎:equals和hashCode方法不再在这样的列表中很好地定义。
问题是List对象的哈希码是递归计算的。
int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
问题是如何使我的代码识别出来并检测List对象(或其某些项目甚至更深层次)是否包含List对象本身。
如何在遍历List对象时保留List对象列表并能够调用contains() - 类似方法?保持System.identityHashCode(对象)并对其进行测试是否足够好?
答案 0 :(得分:4)
System.identityHashCode
会有所帮助,但使用其中一个内置工具按身份跟踪对象几乎肯定会更简单 - IdentityHashMap
。
boolean containsCircularReference(Iterable<?> iterable) {
return containsCircularReference(
iterable,
Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()));
}
private boolean containsCircularReference(Object o, Set<Object> seen) {
if (seen.contains(o)) {
return true;
}
seen.add(o);
if (o instanceof Iterable) {
for (Object o2 : (Iterable<?>) o) {
if (containsCircularReference(o2, seen)) {
return true;
}
}
}
return false;
}
作为参考,您不能依赖System.identityHashCode
无碰撞。对于初学者,您可以在JVM中分配超过2 ^ 32个对象,并且只有2 ^ 32个不同的identityHashCode
可能...
如果它不仅仅是Iterable
中的成员身份,而是任何的任何循环引用,那么变得更难,尽管可以用反射来实现。也就是说,这种循环引用的存在并不一定意味着equals
和hashCode
不起作用;只要equals
和hashCode
方法中的引用是非循环的,并且没有通用的方法来检测它,那么循环引用是完全可以的。