Набор Java Set - метод переопределения равным
Есть ли способ переопределить метод equals
, используемый типом Set
? Я написал собственный метод equals
для класса с именем Fee
. Теперь у меня есть LnkedList
of Fee
, и я хочу убедиться, что нет дублированных записей. Таким образом, я рассматриваю возможность использования Set
insted a LinkedList
, но критерии для определения того, равны ли две сборы, находятся в методе overriden equals
в классе Fee
.
Если вы используете LinkedList
, мне придется перебирать каждый элемент списка и вызывать метод overriden equals
в классе Fee
, а остальные записи - как параметр. Простое чтение этого звука звучит как слишком большая обработка и добавит сложности вычислений.
Можно ли использовать Set
с переопределенным методом equals
? Должен ли я?
Ответы
Ответ 1
Как сказал Джефф Фостер:
Метод Set.equals() используется только для сравнения двух наборов для равенства.
Вы можете использовать Set
, чтобы избавиться от повторяющихся записей, но будьте осторожны: HashSet
не использует методы equals()
своих содержащихся объектов для определения равенства.
A HashSet
содержит внутреннюю запись HashMap
с <Integer(HashCode), Object>
и использует equals(), а также метод equals HashCode для определения равенства.
Один из способов решения проблемы - переопределить hashCode()
в классе, который вы помещаете в Set, чтобы он представлял ваши критерии equals()
Пример:
class Fee {
String name;
public boolean equals(Object o) {
return (o instanceof Fee) && ((Fee)o.getName()).equals(this.getName());
}
public int hashCode() {
return name.hashCode();
}
}
Ответ 2
Вы можете и должны использовать Set для хранения типа объекта с помощью метода переопределенных равных , но вам также может потребоваться переопределить hashCode(). Равные объекты должны иметь одинаковые хэш-коды.
Например:
public Fee{
public String fi;
public String fo;
public int hashCode(){
return fi.hashCode() ^ fo.hashCode();
}
public boolean equals(Object obj){
return fi.equals(obj.fi) && fo.equals(obj.fo);
}
}
(Конечно, с нулевыми проверками).
Установки часто используют hashCode() для оптимизации производительности и будут ошибочно работать, если ваш метод hashCode нарушен. Например, HashSet использует внутренний HashMap.
Если вы проверите исходный код HashMap, вы увидите, что это зависит как от методов hashCode(), так и от equals() элементы для определения равенства:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
Если хэш не сгенерирован правильно, ваш метод equals никогда не может быть вызван.
Чтобы сделать ваш набор быстрее, вы должны генерировать разные хэш-коды для объектов, которые не равны, где это возможно.
Ответ 3
Set
использует метод equals объекта, добавленного в набор. В JavaDoc указано
Коллекция, которая не содержит повторяющихся элементов. Более формально множества не содержат пары элементов e1 и e2 таких, что e1.equals(e2) и не более одного нулевого элемента.
Метод Set.equals()
используется только для сравнения двух наборов для равенства. Он никогда не использовался как часть добавления/удаления элементов из набора.
Ответ 4
Одним из решений было бы использовать TreeSet с помощью компаратора.
Из документации:
Экземпляр TreeSet выполняет все сравнения элементов с помощью метода compareTo (или сравнения), поэтому два элемента, которые считаются равными этому методу, равны с точки зрения множества.
Этот подход будет намного быстрее, чем использование LinkedList, но немного медленнее, чем HashSet (ln (n) vs n).
Стоит отметить, что один из побочных эффектов использования TreeSet заключается в том, что ваш набор будет отсортирован.
Ответ 5
Есть PredicatedList или PredicatedSet в Apache Commons Collection