如何为循环图节点编写hashCode()函数?

时间:2013-12-19 15:54:29

标签: java eclipse hashcode

我有以下用作图表一部分的类:

public class MyNode {

    private String name;

    private Set<MyNode> parents;

    private Set<MyNode> children;

    // getters and setters
}

当我使用Eclipse的Source / Generate hashCode() and equals()时,它会生成此方法:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((children == null) ? 0 : children.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + ((parents == null) ? 0 : parents.hashCode());
    return result;
}

问题在于此方法从当前对象转到其子对象,然后在计算第一个子对象的hashCode()时,它通过{{1}返回到原始节点但是不知道hashCode()已经在那里计算过了。然后它重新进入原始节点的parents.hashCode(),它给出了一个美丽的无限循环。

问题:如何检查children的两个实例是否是同一个对象,同时避免无限循环?为了停止探索,在MyNode类中添加MyNode布尔值是否可以接受?或者有更好的解决方案吗?

谢谢!

3 个答案:

答案 0 :(得分:6)

在实施hashCodeequals时,您不应使用子节点或节点父节点。它们是可变的属性。更改边后,hashCode的计算会有所不同,并会导致地图和集合集合损坏。

仅使用不可变字段实现hashCodeequals,这些字段为对象创建不同的自然键。名称可能是一个很好的候选人,除非它可以改变。

如果不存在不可变字段,则:

  1. 不要覆盖hashCodeequals方法,默认设置就可以了。它将使每个类实例都是唯一的。
  2. 制作一些唯一的ID字段(按sequance)并将其用作hashCode中的种子并在equals中进行比较。

答案 1 :(得分:2)

您可以使用== opearator检查两个对象是否是同一个实例:

if(obj0 == obj1)

如果你想使用visited标志,你应该使用查找(例如Map)来实现它,因为在你的代码运行之后你必须重置这些标志。

我建议忽略parents / children并为每个节点添加唯一的 ID

答案 2 :(得分:2)

hashCode()唯一的硬性要求是两个相等的对象必须返回相同的哈希值。

此实施符合:

@Override
public int hashCode() {
    return 42;
}

...因为没有人说非等同物必须有不同的哈希码。

当然,要正确地完成工作,hashCode()如果价值可以分散,效果会更好。只要你不违反关于平等对象的规则,你就可以做任何你喜欢的事情。在普通的通用代码中,我不希望哈希对性能至关重要,我通常只返回一两个重要字段的哈希码(例如本例中的名称),前提是这些字段涉及计算等于使得相等的对象具有相同的散列。

关键是,你真的需要考虑equalshashCode作为一对,最好从你的equals定义开始。