Java HashMap.containsKey () не вызывает equals () - PullRequest
24 голосов
/ 06 января 2011

У меня есть хэш-карта:

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

Ответы [ 6 ]

41 голосов
/ 06 января 2011

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

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

5 голосов
/ 06 января 2011

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

4 голосов
/ 06 января 2011

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

3 голосов
/ 06 января 2011

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

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

1 голос
/ 06 января 2011

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

Как отметил Абимаран Кугатхасан, реализация 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 для Map относительно использования изменяемых типов для ключей.Не хэш-типы карт не будут иметь этой конкретной проблемы, но могут иметь другие проблемы при изменении ключей на месте.

...