2011-01-06 93 views
21

我有一個HashMap:的Java HashMap.containsKey()不調用equals()方法

Map<LotWaferBean, File> hm = new HashMap<LotWaferBean, File>(); 

LotWaferBean lw = new LotWaferBean(); 
... //populate lw 
if (!hm.containsKey((LotWaferBean) lw)) { 
    hm.put(lw, triggerFiles[l]); 
} 

LotWaferBean代碼:

@Override 
public boolean equals(Object o) { 
     if (!(o instanceof LotWaferBean)) { 
       return false; 
     } 
     if (((LotWaferBean) o).getLotId().equals(lotId) 
        && ((LotWaferBean) o).getWaferNo() == waferNo) { 
       return true; 
     } 
     return false; 
    } 

在我的IDE我把斷點equals()但永遠不會執行。爲什麼?

回答

38

嘗試在hashCode()中放置斷點。

如果map中兩個對象的hashCode()返回相同的數字,那麼會調用equals來確定它們是否真的相等。

+14

更具體地說,如果你實現`equals`方法,你應該實現`hashcode`一個......就像手冊中所寫的那樣:) – 2011-01-06 04:38:21

3

JVM檢查該對象哈希碼的哈希碼桶,如果有更多的對象具有相同的哈希碼,那麼只會執行equals()方法。而且,開發者應該遵循hashCode()和equals()方法之間的正確契約。

5

僅當2個hashCode相等時,equals()將在循環密鑰期間被調用。

3

僅當2個hashCodes相等時,equals()將在循環密鑰期間調用。

這是正確的答案......或差不多。確切地說,如果2個散列碼發生衝突(同樣可以確保它們在適當的散列表impl下發生碰撞),那麼只有進行相等性檢查。

1

順便說一句,你的平等方法很可能是不正確的。如果LotWaferBean被覆蓋,你的equals方法將接受子類實例,但是你的子類也可以嗎?

它更好地應閱讀:

@Override 
public boolean equals(Object o) { 
    if (o == null || o.getClass() != getClass()) { // << this is important 
     return false; 
    } 

    final LotWaferBean other = (LotWaferBean)o; 
    return other.getLotId().equals(lotId) 
       && other.getWaferNo() == waferNo); 
} 
0

由於Abimaran Kugathasan指出,HashMap的實現使用哈希桶高效地查找鍵,並且只使用equals()方法來比較匹配的哈希桶的鑰匙反對給定的關鍵。值得注意的是,當密鑰被添加到HashMap時,密鑰被分配給散列桶。如果您在添加哈希映射後更改哈希映射中的鍵值,將會改變其哈希碼,那麼它們將不在正確的哈希桶中;並嘗試使用匹配鍵訪問映射將找到正確的哈希桶,但它不會包含已更改的鍵。

class aMutableType { 
    private int value; 
    public aMutableType(int originalValue) { 
    this.value = originalValue; 
    } 
    public int getValue() { 
    return this.value; 
    } 
    public void setValue(int newValue) { 
    this.value = newValue; 
    } 
    @Override 
    public boolean equals(Object o) { 
     // ... all the normal tests ... 
     return this.value == ((aMutableType) o).value; 
    } 
    @Override 
    public int hashCode() { 
     return Integer.hashCode(this.value); 
    } 
} 
... 
Map<aMutableType, Integer> aMap = new HashMap<>(); 
aMap.put(new aMutableType(5), 3); // puts key in bucket for hash(5) 
for (aMutableType key : new HashSet<>(aMap.keySet())) 
    key.setValue(key.getValue()+1); // key 5 => 6 
if (aMap.containsKey(new aMutableType(6)) 
    doSomething(); // won't get here, even though 
        // there's a key == 6 in the Map, 
        // because that key is in the hash-bucket for 5 

這可能會導致一些非常奇怪的行爲。您可以在Map.containsKey(theKey)之前設置一個斷點,並查看該Key的值是否與該映射中的鍵匹配,但該鍵的equals()將不會被調用,並且containsKey()將返回false。

如這裏所指出的https://stackoverflow.com/a/21601013,實際上JavaDoc有關使用可變類型鍵的Map的警告。非哈希映射類型不會有這個特殊問題,但當鍵就地改變時可能會有其他問題。