27

我有一个哈希图:

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()但它从未执行过。为什么?

4

6 回答 6

43

尝试在 hashCode() 中设置断点。

如果 map 中两个对象的 hashCode() 返回相同的数字,则将调用 equals 来确定它们是否真的相等。

于 2011-01-06T04:36:24.630 回答
5

只有当 2 个 hashCode 相等时,equals()才会在循环键期间调用。

于 2011-01-06T05:10:40.550 回答
5

JVM检查那个对象的hashcode的hashcode桶,如果有更多的对象具有相同的hashcode,那么只有equals()方法才会被执行。而且,开发人员应该遵循 hashCode() 和 equals() 方法之间的正确约定。

于 2011-01-06T04:41:51.523 回答
3

只有当 2 个 hashCode 相等时,才会在循环键期间调用 equals()。

这是正确的答案......或几乎。准确地说,如果 2 个哈希码发生冲突(相同可确保它们在正确的 hashmap impl 下必然会发生冲突),则仅执行相等性检查。

于 2011-01-06T10:33:52.610 回答
1

顺便说一句,您的 equal 方法很可能是不正确的。如果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);
}
于 2011-01-06T11:18:40.367 回答
0

正如 Abimaran Kugathasan 所指出的,HashMap 实现使用哈希桶来有效地查找键,并且仅使用 equals() 将匹配的哈希桶中的键与给定键进行比较。值得注意的是,当将键添加到 HashMap 时,会将键分配给散列桶。如果在添加后更改 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

这可能会导致一些看起来很奇怪的行为。你可以在 theMap.containsKey(theKey) 之前设置断点,然后看到 theKey 的值与 theMap 中的某个键匹配,但不会调用该键的 equals(),并且 containsKey() 将返回 false。

如此处所述https://stackoverflow.com/a/21601013,实际上有一个警告 JavaDoc for Map 关于使用可变类型的键。非哈希 Map 类型不会有这个特定的问题,但是当键被就地更改时可能会出现其他问题。

于 2016-12-07T04:36:09.240 回答