Laboratorium nr 2 - 6/7 maja 2014

Plan laboratorium

  • Stwórz taga o nazwie laboratorium1 z zadaniem domowym dot. ligretto
  • Sforkuj repozytorium https://bitbucket.org/agata_migalska_pwr/lostinhashset
  • Uruchom klasę ToString i przyjrzyj się jak wygląda wynik działania metody toString
  • Narusz kontrakt pomiędzy implementacją metod equals i hashCode w klasie User tak, żeby test w klasie UserTest przechodził.
  • Zaimplementuj strategie sortowania w klasie DefaultUserService tak, żeby testy w klasie DefaultUserServiceTest przechodziły. Implementacja każdej z dwóch strategii (wg nazwy i wg ilości punktów) powinna być zrealizowana na dwa sposoby - poprzez obiekty funkcyjne i poprzez wyrażenia lambda.

Tagowanie w Gicie

Tagowanie służy do tego, żeby oznaczyć ważne punkty w historii projektu. Jak każdy system kontroli wersji, Git daje też możliwość tworzenia tagów. Tagi w Gicie mogą być lekkie (ang. lightweight) lub adnotowane (ang. annotated). Tagi lekkie to nie więcej niż wskaźnik na konkretny commit, tagi adnotowane to utworzenie pełnego obiektu w repozytorium Gita. Preferowane są tagi adnotowane, ponieważ zawierają też informację o tym kto taga utworzył i kiedy.
git tag - lista wszystkich tagów
git tag -a laboratorium1 -m 'wiadomość' - utworzenie taga o nazwie laboratorium1
Ponieważ git push domyślnie nie wypycha tagów do repozytorium zdalnego, należy zrobić to samodzielnie.
git push origin laboratorium1 - wypchnięcie taga laboratorium1
git push origin --tags - wypchnięcie wszystkich tagów
Podstawowe informacje odnośnie tagów w gicie

Klasa Object i jej metody

toString() : String

Metoda toString() zwraca tekstową reprezentację obiektu. Domyślna implementacja (w klasie Object) zwraca nazwę klasy i hashCode obiektu. Nadpisanie domyślnej implementacji powoduje, że klasa staje się przyjemniejsza w użytkowaniu.

equals(Object) : boolean

Metoda equals służy do sprawdzania równości dwóch obiektów. W domyślnej implementacji obiekt jest równy tylko sam sobie. Metoda ta musi realizować relację równoważności, czyli spełniać poniższe warunki.

  1. Zwrotność - dla dowolnej niepustej referencji x, x.equals(x) musi zwracać true.
  2. Symetryczność - dla dowolnych niepustych referencji x i y, x.equals(y) musi zwracać true wtedy i tylko wtedy gdy y.equals(x) zwraca true.
  3. Przechodniość - dla dowolnych niepustych referencji x,y i z, jeżeli x.equals(y) zwraca true i y.equals(z) zwraca true, to x.equals(z) musi zwracać true.
  4. Spójność - dla dowolnych niepustych referencji x i y, wielokrotne wywołania x.equals(y) zwracają konsekwentnie true lub konsekwentnie false, o ile nie została zmodyfikowana żadna dana wykorzystywana do porównywania obiektów.
  5. Dla dowolnych niepustych referencji x, x.equals(null) musi zwracać false.

hashCode() : int

Jeżeli w klasie została przedefiniowana metoda equals, musisz również przedefiniować hashCode. Pomiędzy oboma metodami istnieje kontrakt, którego naruszenie może mieć nieprzyjemne konsekwencje.
Kontrakt pomiędzy equals i hashCode:

  1. Jeżeli metoda hashCode zostanie kilkakrotnie wywołana na rzecz tego samego obiektu, musi ona konsekwentnie zwracać tę samą liczbę, pod warunkiem, że nie zostaną zmodyfikowane żadne dane wykorzystywane do porównywania obiektów w metodzie equals. Liczba ta nie musi być identyczna w przypadku ponownego uruchomienia tej samej aplikacji.
  2. Jeżeli metoda equals(Object) wykaże, że dwa obiekty są jednakowe, to metoda hashCode dla obu tych obiektów musi zwracać tę samą wartość.
  3. Nie jest wymagane, aby dwa różne obiekty, według porównania za pomocą mody equals(Object), zwracały różne wartości metody hashCode.

Jeżeli nie zostanie przedefiniowana metoda hashCode, naruszone zostanie drugie z kluczowych wymagań - równe obiekty muszą mieć te same kody mieszające.

Porównywanie obiektów

Porównywanie obiektów jest szczególnie przydatne przy sortowaniu. Można je zrealizować na dwa sposoby.

Nadanie obiektom klasy naturalnego porządku

Implementując interfejs Comparable, klasa wskazuje, że jej obiekty mają naturalny porządek.
  public interface Comparable<T> {
     int compareTo(T obj);
  }

Implementacja strategii porównywania

Konkretną implementację strategii osiągamy przez zaimplementowanie interfejsu Comparator i przekazanie tej implementacji do metody sortującej, np. Collections.sort(Collection<T>, Comparator<T>).
  public interface Comparator<T> {
     public int compare(T t1, T t2);
  }

Niezależnie od wyboru sposobu implementacji, metoda porównująca powinna zwracać:

  • całkowitą liczbę ujemną, jeżeli obiekt jest mniejszy,
  • zero, jeżeli obiekt jest równy,
  • całkowitą liczbę dodatnią, jeżeli obiekt jest większy.

Zadanie domowe

Dokończ to, czego nie zdążyliśmy zrealizować na laboratorium i pochwal się wynikami.