2012-02-16 8 views
22

У меня возникла проблема, когда я создаю объект ArrayList из объектов Foo, я переопределяю метод equals, и я не могу получить метод contains для вызова метода equals. Я попробовал переопределить равные и хэш-коды вместе, но он все равно не работает. Я уверен, что есть логическое объяснение, почему это так, но я не могу понять это сейчас на моем собственном lol. Я просто хочу узнать, содержит ли список указанный идентификатор.. Метод Contains() не вызывает метод Overridden equals

Вот код:

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

ВЫВОД: ложные ложные ложные

ответ

34

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

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

но

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

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

Равных методы реализуют отношение эквивалентности ссылок непустого объекта:

  • [...]

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

Это не рефлексивный либо:

  • Это рефлексивный: для любого ненулевого опорного значения 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 к :

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(); 
} 
+0

Я добавил простой хеш-код, все еще не работает ... –

+0

@ReidMac: Я был неправ, это о 'equals()' не будучи симметричным, посмотрите на мое редактирование. 'hashCode()' не имеет никакого отношения к этому случаю, но все же вы должны следовать этому принципу. –

+0

Странно, что нам нужно использовать это соглашение 'new Foo ('ID1');', чтобы использовать собственный метод equals. Любая причина этого? – Dish

4

Вы должны реализовать хэш-код

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

Ваш метод равно должен быть изменен наряду с переопределение функции хэш-код(). В настоящее время вы проверяете, является ли объект, по которому вы сравниваете, экземпляр 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, генерировать хэш-код и составляет для вас будет Source -> Создать хэш-код() и Equals() ...

+1

+1, я скопировал фрагмент кода в свой ответ, надеюсь, вы не против. –

Смежные вопросы