.Contains () метод, не вызывающий переопределенный метод equals - PullRequest
26 голосов
/ 17 февраля 2012

У меня проблема с созданием ArrayList объектов Foo, я переопределяю метод equals и не могу получить метод содержимого для вызова метода equals.Я попытался переопределить equals и hashcode вместе, но это все еще не работает.Я уверен, что есть логическое объяснение, почему это так, но я не могу понять это в данный момент на свой страх и риск.Я просто хочу, чтобы увидеть, если список содержит указанный идентификатор.

Вот некоторый код:

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;
    }
}

ВЫХОД: ложно ложно ложно

Ответы [ 3 ]

43 голосов
/ 17 февраля 2012

Это потому, что ваш equals() не является симметричным :

new Foo("ID1").equals("ID1");

, но

"ID1".equals(new Foo("ID1"));

не соответствует действительности.Это нарушает контракт equals():

Метод equals реализует отношение эквивалентности для ненулевых ссылок на объекты:

  • [...]

  • симметричный : для любых ненулевых опорных значений x и y, x.equals(y) должен возвращать true, если и толькоесли y.equals(x) возвращает true.

Это не Возврат либо:

  • Это рефлексивно :. для любого ненулевого опорного значения x x.equals(x) должна вернуть истинный * * * 1046 1047
1049

@ 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();
}
11 голосов
/ 17 февраля 2012

Ваш метод 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 и equals для вас, выбрав Source -> Generate hashcode () и equals () ...

5 голосов
/ 17 февраля 2012

Вы должны реализовать hashCode

@Override
public int hashCode() {
    return id.hashCode();
}

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

Использование равно

@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")));
...