Witam,
W języku Java, jest fajna metoda – equals(). Służy ona do porównywania, czy dwa obiekty są sobie równe. Czyli, na przykład obiekt Osoba implementuje metodę equals, i sprawdza czy imię i nazwisko tej osoby są takie same. Implementując metodę equals, należy pamiętać, że może z niej korzystać nie tylko Twój kod, ale także kod innych bibliotek do których przekazujesz obiekty, np.: Hibernate, JiBX, Axis. Implementując metodę equals w tworzonym właśnie obiekcie, należy pamiętać, że Java spodziewa się określonego działania tej metody.
Dla metody equals określono 5 bardzo logicznych warunków. A więc:
- metoda equals musi być zwrotna, czyli a.equals(a)==true.
- metoda equals musi być symetryczna, czyli a.equals(b)==b.equals(a).
- metoda equals musi być przechodnia, czyli jeżeli a.eqauls(b)==true i b.equals(c)==true to a.equals(c)==true. (Jednak gdy: a.equals(b)==false i b.equals(c)==false to a.equals(c) może być true)
- metoda equals musi być konsekwenta, czyli gdy dwa razy (w różnych chwilach czasu) porównujemy te same obiekty, to wynik tego porównania powinien być taki sam.
- obiekt jest nie równy null, czyli a.equals(null)==false dla każdego a nie będącego null
Wszystkie te warunki są tak samo ważne, jednak 3 pierwsze dają największe pole do popełnienia błędów. Błędne działanie metody equals, może być trudne do wykrycia i często będzie wyglądać jak błąd w innej bibliotece. Wyobraźmy sobie, że na przykład
JiBX (taka biblioteka do serializacji do XMLa) podczas serializacji złożonej struktury danych zapisuje sobie gdzieś, jakie obiekty były już serializowany, tak by nie serializować dwa razy tego samego obiektu. Tymczasem metoda equals oszukuje, i JiBX próbuje 1000 razy marshalować ten sam obiekt. Programista zobaczy komunikat o braku pamięci, pomyśli – j… OpenSource – nic nie działa – tymczasem błąd może tkwić w jego kodzie w tak oczywistej metodzie equals. To oczywiście tylko hipoteza, ale tak może być.
Proponuję pisać metodę equals na przykład tak.
public class Osoba {
private String imie;
private String nazwisko;
public boolean equals(Object innyObiekt) {
if (this == innyObiekt) return true;
if (!( this.getClass().equals(innyObiekt.getClass()) )) return false;
Osoba innaOsoba = (Osoba) innyObiekt;
return (null == getImie() ? null == innaOsoba.getImie() : getImie()
.equals(innaOsoba.getImie()))
&& (null == getNazwisko() ? null == innaOsoba.getNazwisko()
: getNazwisko().equals(innaOsoba.getNazwisko()));
}
Warto zapamiętać bardzo ładną konstrukcję:
a==null ? b==null : a.equals(b) . Zaoszczędzi nam ona sporo pisania.
Dla skomplikowanej metody equals należy pisać test, np. coś takiego:
public class OsobaTest {
@Test
public void testEqualsObject() {
Osoba antek1 = new Osoba();
antek1.setImie("Antek");
assertTrue("Zwrotna",antek1.equals(antek1));
Osoba ola = new Osoba();
ola.setImie("Ola");
assertFalse("Antek to nie Ola",antek1.equals(ola));
Osoba antek2 = new Osoba();
antek2.setImie("Antek");
assertTrue("Antek to Antek2",antek1.equals(antek2));
assertTrue("Symetryczna",antek1.equals(antek2)&&antek2.equals(antek1));
Osoba antek3 = new Osoba();
antek3.setImie("Antek");
assertTrue("Antek to Antek",antek2.equals(antek3));
assertTrue("Przechodnia",
antek1.equals(antek2)==true&&antek2.equals(antek3)&&antek1.equals(antek3));
assertFalse("Antek to nie null",antek1.equals(null));
}
}
Jak widać, z prostą metodą equals może być dużo zabawy. Jednak to bardzo ważne, żeby jej nie zepsuć. Inaczej nasz obiekt, nie będzie działał prawidłowo w świecie Java. Na zakończenie dodam, że warto też poczytać o metodzie
hashCode().
Pozdrawiam