2016-12-04 26 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()和矛盾的結果一起

相關問題