Равенство между 2 HashMap

В методе equals() моего класса я использую частную переменную HashMap для сравнения на равенство. Тем не менее, 2 разных объекта по-прежнему показывают равные при сравнении их переменных HashMap. Дальнейшие исследования привели меня к ссылке: Ссылка здесь. Однако это просто говорит о том, что причина того, что HashMap1.equals(HashMap2) не работает, заключается в том, что "очевидно, что массивы Java нельзя проверить на равенство без написания настраиваемого кода".

Я не понял эту причину. Может ли кто-нибудь, пожалуйста, привести меня к сложной причине?

Ответ 1

Метод equals для типа массива Java эквивалентен ==, поскольку "классы" массива Java не переопределяют Object.equals.

Если вы хотите сравнивать массивы "по значению", вам нужно либо использовать соответствующий метод java.util.Arrays.equals(...), либо реализовать его самостоятельно.

Если ваш HashMap использует массивы в качестве ключей или значений, то он вызовет метод массива equals, чтобы проверить, совпадают ли ключи и/или значения между двумя картами. Это заставит HashMap.equals вести себя странно (с вашей точки зрения). Вот что говорит связанная статья. Однако семантика массива влияет на равенство HashMap только в том случае, если вы используете массивы в качестве классов ключей или значений. Если вы этого не сделаете, то HashMap::equals должен просто работать как положено.

Javadocs для равенства в классах Map немного вовлечены, но они в основном сводятся к тому, чтобы взять два набора записей, сравнить их размеры и затем выполнить s1.containsAll(s2). Конечно, это дорого, но оно должно работать для всех классов Map, которые правильно реализуют интерфейс Map.


Обратите внимание, что использование массивов в качестве ключей для карт является плохой идеей по нескольким причинам:

  1. Семантика массивов equals и hashCode неверна для HashMap в большинстве сценариев. В большинстве случаев вам нужна карта для сравнения ключей по значению, а не по идентификатору объекта.
  2. Массивы изменчивы. Если предположить, что для решения проблемы equals/hashcode существует обходное решение, вы все равно можете нарушить инварианты карты, изменив ключ массива.

Ответ 2

Статья правильная. Хэшмапы можно безопасно сравнивать с помощью метода equals(), если ключевые объекты и объекты значений можно сравнивать с использованием того же метода. В статье значениями карты являются массивы, которые не реализуют equals(), как ожидалось. Вместо этого использование ArrayList решило бы проблему.

Ответ 3

Нативные массивы Java не имеют функции .equals(). Поэтому, если ваши значения hashmap (или ключи, которые, я полагаю), являются массивами, HashMap.equals() завершится с ошибкой. Я подозреваю, что он вернется к Object.equals(), который просто проверяет, являются ли оба объекта фактически одним и тем же объектом.

// something like this
class Object {
  public boolean equals( Object o) {
    return this == o;
  }
}

Вы можете обойти проблему, используя какой-то вариант в контейнере, а не в виде массива [], поскольку у контейнеров есть свой .equals(), который вызывает equals() на последовательных элементах контейнеров, а не просто проверяет, та же ссылка. Код для реализации Collection.equals может выглядеть примерно так:

public boolean equals(Object o) {
  // sets never equal lists and visa versa
  if (o instanceof MyCollectionSubclass) {
    Iterator myIterator = iterator();
    Iterator theirIterator = ((Collection)o).iterator();
    while (myIterator.hasNext() && theirIterator.hasNext()) {
      Object myObj = myIterator.next();
      Object theirObj = theirIterator.next();
      if (!myObj.equals(theirObj)) {
        return false;
      }
    }
    // at least one will be false or we wouldn't have left the above while loop
    return myIterator.hasNext() == theirIterator.hasNext();
  }
  // not our class
  return false;
}

Это может привести к истинному сопоставлению значений в зависимости от того, что делает содержимое коллекции, когда вы вызываете их equals().

Ответ 4

Массивы Java не могут быть проверены на равенство без написания настраиваемого кода

Это просто сложный способ сказать, что массивы Java не переопределяют Object.equals(). Следовательно, если вы сравниваете их с помощью equals() (это то, что делают методы equals для всех классов коллекции), вы получаете "равенство экземпляра" вместо "равенства значений".

Это действительно просто особый случай разных способов equals работает в зависимости от того, было ли оно переопределено или нет.