Подтвердить что ты не робот

Java HashMap.containsKey() не вызывает equals()

У меня есть hashmap:

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(), но он никогда не выполняется. Зачем?

4b9b3361

Ответ 1

Попробуйте поставить точку останова в hashCode().

Если hashCode() из двух объектов в карте возвращает одинаковое число, тогда будут вызываться равенства, чтобы определить, действительно ли они равны.

Ответ 2

Только если 2 хэш-кода равны, equals() будет вызываться во время циклов.

Ответ 3

JVM проверяет ведро hashcode этого хэш-кода объекта, если есть больше объектов с одним и тем же хэш-кодом, тогда только метод equals() будет выполнен. И разработчик должен следовать правильному контракту между методами hashCode() и equals().

Ответ 4

Только если 2 hashCodes равны, equals() будет вызываться во время клавиш цикла.

это правильный ответ... или почти. Точно так, если два хэш-кода сталкиваются (одинаково гарантируют, что они обязательно столкнутся при правильной импровизации hashmap), только тогда выполняется проверка равенства.

Ответ 5

Кстати, ваш равный метод, скорее всего, неверен. В случае переопределения 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);
}

Ответ 6

Как отметил Абимаран Кугатсан, реализация 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 a key == 6 in the Map,
                    // because that key is in the hash-bucket for 5

Это может привести к некоторому довольно странному поведению. Вы можете установить точку останова непосредственно перед theMap.containsKey(theKey) и увидеть, что значение ключа совпадает с ключом в Map, и все же ключ equals() не будет вызываться, а containsKey() вернет false.

Как отмечено здесь fooobar.com/info/218987/..., на самом деле есть предупреждение JavaDoc для Map относительно использования изменяемых типов для ключей. Типы не-хэш-карт не будут иметь этой конкретной проблемы, но могут иметь другие проблемы, когда ключи изменены на месте.