Porovnávání objektů

  • Test na rovnost/nerovnost lze použít na porovnávání primitivních hodnot i objektů: ==, !=

  • Na objekty nelze použít operátory porovnání "dle velikosti", tzn. <, <=, >=, > — ani to nelze dodefinovat jako v C++.

Jak chápat rovnost objektů

Warning
  • u porovnávání objektů == vrací true jen při rovnosti odkazů, neboli když oba odkazy ukazují na přesně tentýž objekt, tj. jsou-li objekty identické.

  • Rovnost obsahu (tedy jakási "rovnocennost", ekvivalence) objektů se zjišťuje voláním metody o1.equals(Object o2)

Porovnávání objektů pomocí ==

Použití == na objekty:

  • Porovnáme-li dva objekty (tzn. odkazy na objekty) prostřednictvím operátoru == dostaneme rovnost jen v případě, jedná-li se o dva odkazy na tentýž objekt — tj. dva totožné objekty.

  • Jedná-li se o dva obsahově stejné objekty, ale existující samostatně, pak == vrátí false.

Porovnávání objektů dle obsahu

  • Chceme-li (intuitivně) chápat rovnost objektů podle obsahu, tj.

  • dva objekty jsou rovné (rovnocenné, nikoli totožné), mají-li stejný obsah, pak

  • musíme pro danou třídu překrýt metodu equals, která musí vrátit true, právě když se obsah výchozího a srovnávaného objektu rovná.

  • Fungování equals lze srovnat s porovnáváním dvou databázových záznamů podle primárního klíče.

  • Nepřekryjeme-li equals, funguje původní equals přísným způsobem, tj. rovné si budou jen totožné objekty .

Příklad porovnávání objektů

Objekt třídy Person nese informace o člověku. Zde dva objekty položíme stejné (rovnocenné), nesou-li stejná příjmení.

public class Person {
   private String firstname;
   private String surname;
   public Person (String j, String p) {
      firstname = j; surname = p;
   }
   public boolean equals(Object o) {
      if (o instanceof Person) {
         Person c = (Person)o;
         // dva lidé se rovnají, mají-li stejná příjmení
         return surname.equals(c.surname);
      } else {
         // porovnáváme-li osobu s ne-osobou...
         return false;
      }
   }
}

Metoda hashCode

  • S překrytím metody equals vyvstává jeden dosud nezaznamenaný problém.

  • Jakmile u třídy překryjeme metodu equals, měli bychom současně překrýt i metodu hashCode. Tato metoda vrací celé číslo (int) co nejlépe charakterizující obsah objektu tak, aby:

    1. pro dva stejné (dle equals) objekty musí vždy vrátit stejnou hodnotu.

    2. Pro dva obsahově různé objekty by hashCode naopak měla vracet různé hodnoty, což ale není stoprocentně nezbytné a ani nemůže být vždy splněno.

Note

Metoda hashCode totiž nemůže obecně vždy být prostá — všechny složitější třídy mají potenciálně více možných hodnot (různých objektů) než je všech hodnot typu int, které hashCode vrací.

Příklad hashCode

  • V těle hashCode námi definované třídy s oblibou delegujeme řešení na volání hashCode jednotlivých složek našeho objektu

  • a to těch, které figurují v equals. Rozšíříme minulý příklad.

    public class Person {
       private String firstname;
       private String surname;
       public Person (String firstname, String surname) {
          this.firstname = firstname; this.surname = surname;
       }
       public boolean equals(Object o) {
          // zde zůstává porovnání příjmení
       }
       // nyní ale doplňujeme překrytí hashCode
       public int hashCode() {
          // které využívá volání hashCode na příjmení,
          // protože jedině příjmení využíváme v equals
          return surname.hashCode();
       }
    }