Можете ли вы объяснить это столкновение ключей хэш-карты Java? - PullRequest
0 голосов
/ 02 декабря 2010

У меня есть HashMap, и он используется следующим образом:

HashMap<SomeInterface, UniqueObject> m_map;

UniqueObject getUniqueObject(SomeInterface keyObject)
{
     if (m_map.containsKey(keyObject))
     {
         return m_map.get(keyObject);
     }
     else
     {
         return makeUniqueObjectFor(keyObject);
     }
}

Моя проблема в том, что я вижу несколько объектов разных классов, соответствующих одному и тому же ключу в m_map.containsKey (keyObject).

Итак, вот мои вопросы:

  1. Возможно ли это? Интерфейс Map говорит, что он использует equals () для сравнения, если ключ не нулевой. Я не переопределил equals () ни в одном из моих классов SomeInterface. Означает ли это, что метод equals может быть неправильным?

  2. Если приведенное выше верно, как я могу заставить HashMap возвращать true только на equals (), если они на самом деле являются одним и тем же объектом, а не копией? Возможно ли это сказать, если (объект1 == объект2)? В начале разработки Java мне сказали, что я должен избегать этого, но я так и не узнал, когда это следует использовать.

Заранее спасибо. :)

Ответы [ 5 ]

6 голосов
/ 02 декабря 2010

Я сильно подозреваю, что вы неправильно диагностировали проблему. Если вы нигде не переопределяете equals (и вы не подклассифицируете что-либо еще, что переопределяет equals), тогда у вас действительно должно быть поведение «идентичности».

Я был бы шокирован, узнав, что это был не тот случай, если честно.

Если вы можете создать короткую, но законченную программу, которая демонстрирует проблему, с которой было бы легче разобраться - но на данный момент, я бы определенно дважды проверил ваши подозрения о видении различных объектов. рассматриваются как равные ключи.

3 голосов
/ 02 декабря 2010

Реализация по умолчанию equals() выполняется в java.lang.Object:

public boolean equals(Object obj) {
return (this == obj);
}

Другой метод hashCode(); по умолчанию возвращает какую-то ссылку на объект. То есть оба уникальны по умолчанию. Equals возвращает true только для одного и того же объекта, hashCode () отличается для каждого объекта.

Это именно то, что может создать несколько записей. Вы можете создать 2 экземпляра вашего класса. С вашей точки зрения они равны, потому что содержат одинаковые данные. Но они разные. Итак, если вы используете эти объекты в качестве ключей карты, вы создаете 2 записи. Если вы хотите избежать этого, используйте equals и hashCode для вашего класса.

Эта реализация иногда очень многословна. HashCodeBuilder и EqualsBuilder из проекта Джакарта могут вам помочь. Вот пример:

@Override
public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object other) {
    return EqualsBuilder.reflectionEquals(this, other);
}

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this);
}
0 голосов
/ 02 декабря 2010

К вашему сведению, у вас могут быть IDE, такие как Eclipse, для создания методов hashCode & equals.Вероятно, они справятся с работой лучше, чем если бы вы попытались написать их вручную.

0 голосов
/ 02 декабря 2010

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

Обратите внимание, что HashMap не только использует equals(), но и hashCode(). Ваш метод hashCode() должен быть правильно реализован, чтобы соответствовать реализации метода equals(). Если реализация этих методов не совпадает, вы можете получить непредсказуемые проблемы.

Подробные требования см. В описании equals() и hashCode() в документации API класса Object.

0 голосов
/ 02 декабря 2010

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

...