2014-12-05 54 views
0

據我已閱讀,HashMap的不正確的equals和hashCode實現

使用對象爲重點,以一個HashMap,它必須提供正確的 覆蓋和執行等於hashCode 方法。 HashMap中獲得(密鑰K)方法調用鍵 對象的hashCode方法和適用返回散列值自身的靜態哈希 功能找到一個桶的位置(備份陣列),其中鍵和 值存儲在形式稱爲Entry(Map.Entry)的嵌套類。 HashMap的內部散列方法防止質量差的散列 函數。

爲了測試這些合同,我寫了一個bean類的不正確,但法律的實施等於的hashCode方法。

類:

public class HashVO { 

    private String studentName; 
    private int age; 
    private boolean isAdult; 

    public HashVO(String studentName, int age, boolean isAdult) { 
     super(); 
     this.studentName = studentName; 
     this.age = age; 
     this.isAdult = isAdult; 
    } 
    public String getStudentName() { 
     return studentName; 
    } 
    public void setStudentName(String studentName) { 
     this.studentName = studentName; 
    } 
    public int getAge() { 
     return age; 
    } 
    public void setAge(int age) { 
     this.age = age; 
    } 
    public boolean isAdult() { 
     return isAdult; 
    } 
    public void setAdult(boolean isAdult) { 
     this.isAdult = isAdult; 
    } 
    @Override 
    public String toString() { 
     return studentName + " : " + age + " : " + isAdult; 
    } 
    @Override 
    public boolean equals(Object obj) { 
     return false; 
    } 
    @Override 
    public int hashCode() { 
     return 31; 
    } 

} 

在這種情況下,HashMap中的散列法,

static final int hash(Object key) { 
     int h; 
     return (key == null) ? 0 : (h = key.hashCode())^(h >>> 16); 
    } 

也應該返回相同的值,因爲每次的散列碼總是返回31.因此,如果對象類HashVO被用作hashMap的鍵,get方法不應該工作,因爲它應該去同一個桶來檢索對象,並且equals方法總是返回false,所以它將不能夠找到匹配fo r關鍵對象

但是,當我使用這個方法,

public static void main(String[] args) { 
     HashMap<HashVO, String> voMap = new HashMap<HashVO, String>(); 
     HashVO vo = new HashVO("Item1", 25, true); 
     HashVO vo1 = new HashVO("Item2", 12, false); 
     HashVO vo2 = new HashVO("Item3", 1, false); 
     voMap.put(vo, "Item"); 
     voMap.put(vo1, "Item1"); 
     voMap.put(vo2, "Item2"); 
     System.out.println(voMap.get(vo)); 
     System.out.println(voMap.get(vo1)); 
     System.out.println(voMap.get(vo2)); 
    } 

的輸出是正確的,並顯示

Item 
Item1 
Item2 

我想知道爲什麼這個正確的輸出甚至未來的equals和hashCode方法實施是不正確的。

回答

2

HashMap有一個小技巧,它在使用equals之前比較了對象引用。由於您使用相同的對象引用來添加元素並檢索它們,因此HashMap將正確返回它們。

請參閱Java 7的源here(Java的8做了HashMap一個相當大的改造,但它類似的東西)

final Entry<K,V> getEntry(Object key) { 
    if (size == 0) { 
     return null; 
    } 

    int hash = (key == null) ? 0 : hash(key); 
    for (Entry<K,V> e = table[indexFor(hash, table.length)]; 
     e != null; 
     e = e.next) { 
     Object k; 
     // HERE. Uses == with the key 
     if (e.hash == hash && 
      ((k = e.key) == key || (key != null && key.equals(k)))) 
      return e; 
    } 
    return null; 
} 

請注意,這不是文檔的一部分,所以不依賴於它。

+0

我認爲你是對的。我使用Java 8來運行程序。 Java 8中的HashMap在getNode方法中也有類似的實現(行:566)。 – Dripto 2014-12-05 15:50:46

0

HashMap中是這樣的:

1)表格單元,其中(鍵,值)將節省計算作爲key.hashCode指數();

2)HashMap中的鍵通過equals()或通過引用比較進行比較。

因此,在你的情況下,(K,V)的所有對將作爲LinkedList存儲在HashMap表的一個單元中。 而你可以從地圖得到它們,因爲按鍵的引用將等於

相關問題