.Contains() не вызывает метод Overridden equals
У меня возникает проблема, когда я создаю объект ArrayList из объектов Foo, я переопределяю метод equals, и я не могу получить метод contains для вызова метода equals. Я попробовал переопределить равные и хэш-коды вместе, но он все равно не работает. Я уверен, что есть логическое объяснение, почему это так, но я не могу понять это сейчас на моем собственном lol. Я просто хочу, чтобы увидеть, содержит ли список указанный идентификатор.
Вот код:
import java.util.ArrayList;
import java.util.List;
public class Foo {
private String id;
public static void main(String... args){
Foo a = new Foo("ID1");
Foo b = new Foo("ID2");
Foo c = new Foo("ID3");
List<Foo> fooList = new ArrayList<Foo>();
fooList.add(a);
fooList.add(b);
fooList.add(c);
System.out.println(fooList.contains("ID1"));
System.out.println(fooList.contains("ID2"));
System.out.println(fooList.contains("ID5"));
}
public Foo(String id){
this.id = id;
}
@Override
public boolean equals(Object o){
if(o instanceof String){
String toCompare = (String) o;
return id.equals(toCompare);
}
return false;
}
@Override
public int hashCode(){
return 1;
}
}
ВЫВОД:
ложный
ложный
ложь
Ответы
Ответ 1
Это потому, что ваш equals()
не симметричный:
new Foo("ID1").equals("ID1");
но
"ID1".equals(new Foo("ID1"));
неверно. Это нарушает договор equals()
:
Метод equals реализует отношение эквивалентности для ненулевых ссылок на объекты:
Это не рефлексивный:
- Это рефлексивно: для любого ненулевого опорного значения
x
, x.equals(x)
должна возвращать истинное.
Foo foo = new Foo("ID1");
foo.equals(foo) //false!
@mbockus обеспечивает правильную реализацию equals()
:
public boolean equals(Object o){
if(o instanceof Foo){
Foo toCompare = (Foo) o;
return this.id.equals(toCompare.id);
}
return false;
}
но теперь вы должны передать экземпляр Foo
в contains()
:
System.out.println(fooList.contains(new Foo("ID1")));
System.out.println(fooList.contains(new Foo("ID2")));
System.out.println(fooList.contains(new Foo("ID5")));
Наконец, вы должны реализовать hashCode()
для обеспечения согласованных результатов (если два объекта равны, они должны иметь равный hashCode()
):
@Override
public int hashCode() {
return id.hashCode();
}
Ответ 2
Ваш метод equals должен быть изменен вместе с переопределением функции hashCode(). В настоящее время вы проверяете, является ли объект, по которому вы сравниваете, экземпляр String, когда вам нужно проверять объекты Foo.
public boolean equals(Object o){
if(o instanceof Foo){
Foo toCompare = (Foo) o;
return this.id.equals(toCompare.id);
}
return false;
}
Если вы используете Eclipse, я бы рекомендовал, чтобы Eclipse генерировал hashCode и равным вам, перейдя в Source → Generate hashcode() и equals()...
Ответ 3
Вы должны реализовать hashCode
@Override
public int hashCode() {
return id.hashCode();
}
даже несмотря на то, что содержимое работает без ArrayList. Ваши большие проблемы состоят в том, что ваши равные ожидания ожидают String, а не объекты Foo и которые вы запрашиваете, содержит строки. Если реализация спросила каждого извлечения в списке, если они были равны строке, которую вы отправляете, тогда ваш код мог бы работать, но реализация запрашивает строку, если она равна вашим объектам Foo, которых, конечно же, нет.
Используйте equals
@Override
public boolean equals(Object o){
if(o instanceof Foo){
String toCompare = ((Foo) o).id;
return id.equals(toCompare);
}
return false;
}
а затем проверьте, содержит
System.out.println(fooList.contains(new Foo("ID1")));