2016-12-04 44 views
2
class Node{ 
    int x, y, value; 
    Node(int x, int y, int v) { 
     this.x = x; 
     this.y = y; 
     value = v; 
    } 

    @Override 
    public boolean equals(Object o) { 
     Node n = (Node)o; 
     boolean result = this.x == n.x && this.y == n.y && this.value == n.value; 
     return result; 
    } 
} 

void test() { 
    HashSet<Node> s = new HashSet<>(); 
    Node n2 = new Node(1, 1, 11); 
    Node n1 = new Node(1, 1, 11); 
    s.add(n1); 
    System.out.println(s.contains(n2)); 
    System.out.println(n1.equals(n2)); 
} 

回报:HashSet的说,它不包含的元素,尽管等于返回true

真正

https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html#contains-java.lang.Object-,HashSet的使用等来判断它是否包含一个元素。那么包含调用不应该在这里返回true吗?我错过了什么?谢谢。

+3

你也必须重写'hashCode()'。 – Eran

回答

3

参见Object.equals()的Javadoc:

注意,这是通常需要覆盖每当这个方法被覆盖hashCode方法,以便维持用于hashCode方法一般合同,其中指出,等于对象必须有相同的哈希码。

这就是你的班级所缺少的!这个here可以给你一些想法如何hashCode()你的课程。

3

我觉得第一件事就是你以不恰当的方式凌驾平等。你不考虑,比较引用,空对象或类本身。

这样的事情是缺少您的equals方法:

if (this == obj) 
    return true; 
if (obj == null) 
    return false; 
if (getClass() != obj.getClass()) 
    return false; 

在另一方面,你必须正确地实现Node类合同:即你需要重写等于和hashCode

0

我会解释你为什么要重写hashcode(),对此,基本上你需要了解HashSet的工作原理。

首先,因为您不重写hashcode(),您的Node类将从java.lang.Object类获得默认实现。

您可以在equals()添加System.out.println和打印两个Node对象的散列码,如下图所示:

@Override 
public boolean equals(Object o) { 
    Node n = (Node)o; 
    //Add System.out.println to check the hashcodes 
    System.out.println(n.hashCode()+"::::::"+this.hashCode()); 

    boolean result = this.x == n.x && this.y == n.y && this.value == n.value; 
    return result; 
} 

您可以通过运行上述方法检查输出,你会看到的两个对象的哈希码是不同的,也就是说,这证明两个对象是相同的,但是它们的哈希码不同

现在来到hashSet.contains(n2)HashSet如何工作是它存储的对象基于其哈希码不同的桶。所以你的两个Node对象将归入两个不同的桶中,并且将返回false

因此,要总结,规则是相等对象必须具有相等的散列码,所以你总是需要重写hashcode()equals(),这样你就不会得到像上述equals()和矛盾的结果一起

相关问题