2012-02-16 7 views
22

Mam problem, w którym tworzę ArrayList obiektów Foo, nadpisuję metodę równości, i nie mogę uzyskać metody contains, która wywoła metodę equals. Próbowałem overriding equals i hashcode razem, ale nadal nie działa. Jestem pewien, że istnieje logiczne wytłumaczenie, dlaczego tak jest, ale nie mogę tego teraz zrozumieć na moim własnym LOL. Chcę tylko sposób sprawdzenia, czy lista zawiera określony identyfikator..Contains() metoda nie wywoływanie Overridden równa się metoda

Oto niektóre kodu:

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

WYJŚCIE: false false fałszywe

Odpowiedz

34

To dlatego, że nie jest equals() symetryczny:

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

ale

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

nie jest prawdą. To narusza umowę equals():

równości metoda implementuje relacją równoważności na non null odniesienia obiektu:

  • [...]

  • Jest symetryczny: dla wszelkie niezerowe wartości odniesienia x i y, x.equals(y) powinny zwracać wartość true wtedy i tylko wtedy, gdy y.equals(x) zwraca true.

Nie jest odruchowy albo:

  • Jest odruchowy: dla każdego niepuste wartości referencyjnej x, x.equals(x) powinien powrócić prawda.
Foo foo = new Foo("ID1"); 
foo.equals(foo) //false! 

@mbockus zapewnia prawidłową realizację equals():

public boolean equals(Object o){ 
    if(o instanceof Foo){ 
    Foo toCompare = (Foo) o; 
    return this.id.equals(toCompare.id); 
    } 
    return false; 
} 

ale teraz musi przejść instancję Foo do :

System.out.println(fooList.contains(new Foo("ID1"))); 
System.out.println(fooList.contains(new Foo("ID2"))); 
System.out.println(fooList.contains(new Foo("ID5"))); 

Wreszcie należy wdrożyć hashCode() aby zapewnić spójne wyniki (jeśli dwa obiekty są równe, muszą mieć równe hashCode()):

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

Dodałem prosty kod skrótu, nadal nie działa ... –

+0

@ReidMac: Myliłem się, chodzi o to, że 'equals()' nie jest symetryczny, spójrz na moją edycję. 'hashCode()' nie ma nic do zrobienia w tym przypadku, ale powinieneś postępować zgodnie z tą zasadą –

+0

Dziwne, że musimy użyć tej nowej konwencji Foo ("ID1"); 'do użycia metody custom equals. Jakiś powód tego? – Dish

4

Należy zaimplementować hashCode

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

choć zawiera utwory na ArrayList bez tego. Twoje duże problemy polegają na tym, że twoi rówieśnicy oczekują ciągów, a nie obiektów Foo, i że prosisz o to, aby zawierały ciągi. Jeśli implementacja zapytała każdego wysunięcia na liście, czy były one równe wysyłanym ciągom znaków, kod mógł zadziałać, ale implementacja zadaje ciąg, jeśli jest równy twoim obiektom Foo, których oczywiście nie ma.

Zastosowanie równa

@Override 
public boolean equals(Object o){ 
    if(o instanceof Foo){ 
     String toCompare = ((Foo) o).id; 
     return id.equals(toCompare); 
    } 
    return false; 
} 

a następnie sprawdzić zawiera

System.out.println(fooList.contains(new Foo("ID1"))); 
9

Twoja metoda equals musi być zmieniane wraz z nadrzędnymi funkcję hashCode(). Obecnie sprawdzasz, czy obiekt, z którym się porównujesz, jest instancją String, kiedy musisz sprawdzać obiekty Foo.

public boolean equals(Object o){ 
    if(o instanceof Foo){ 
     Foo toCompare = (Foo) o; 
     return this.id.equals(toCompare.id); 
    } 
    return false; 
} 

Jeśli używasz Eclipse, polecam posiadające Eclipse wygenerowania hashCode i równa dla Ciebie przechodząc do Źródła -> Generowanie hashcode() i equals() ...

+1

+1, skopiowałem twój fragment kodu do mojej odpowiedzi, mam nadzieję, że nie masz nic przeciwko. –