Равенство между 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
.
Обратите внимание, что использование массивов в качестве ключей для карт является плохой идеей по нескольким причинам:
- Семантика массивов
equals
и hashCode
неверна для HashMap
в большинстве сценариев. В большинстве случаев вам нужна карта для сравнения ключей по значению, а не по идентификатору объекта.
- Массивы изменчивы. Если предположить, что для решения проблемы
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
работает в зависимости от того, было ли оно переопределено или нет.