15.2. Metody equals, hashCode, toString
Klasy przypadku mogą definiować własne wersje metod equals, hashCode i toString, ale jeśli tego nie zrobią, to zostaną automatycznie wyposażone w domyślne implementacje tych metod. Domyślne metody equals, hashCode i toString w swoim działaniu biorą pod uwagę wartości elementów instancji klasy, natomiast argumenty innych, niż pierwsza lista parametrów oraz wartości składowych klasy w niej zdefiniowanych nie są przez nie brane pod uwagę. Plik CaseClassA.scala definiuje klasę przypadku A, która oprócz elementów ma zdefiniowane parametry na drugiej liście parametrów oraz definiuje składową f.
Plik CaseClassA.scala: case class A(a:Int, b:String, c:Long)(d:Int, val e:String) { var f = a + d }
Poniższe dwie instancje klasy A są traktowane jako równe, mimo posiadania innych wartości parametrów d i e oraz składowej f. Mają również równe wartości hashCode oraz takie same reprezentacje tekstowe.
scala> val a1 = new A(1,"a",2L)(4,"a1") a1: A = A(1,a,2) scala> val a2 = new A(1,"a",2L)(6,"a2") a2: A = A(1,a,2) scala> a1.f == a2.f res0: Boolean = false scala> a1 == a2 res1: Boolean = true scala> a1.hashCode == a2.hashCode res2: Boolean = true scala> a1.toString == a2.toString res3: Boolean = true
Jeśli klasa przypadku definiuje własne wersje metod equals, hashCode lub toString, to te wersje mają pierwszeństwo przed domyślnie generowanymi wersjami. Klasa przypadku B, zdefiniowana w pliku CaseClassB.scala, definiuje wspomniane metody, odwołując się w nich do metod zdefiniowanych w klasie nadrzędnej, czyli w tym przypadku AnyRef.
Plik CaseClassB.scala: case class B(a:Int, b:String, c:Long) { override def equals(that: Any) = super.equals(that) override def hashCode = super.hashCode override def toString = super.toString }
W rezultacie, dwie instancje klasy są traktowane jako różne, mimo posiadania takich samych wartości elementów. Podobnie wartości hashCode oraz reprezentacje tekstowe obu instancji są różne.
scala> val b1 = new B(1,"b",2L) b1: B = B@9c38eb scala> val b2 = new B(1,"b",2L) b2: B = B@dda234 scala> b1 != b2 res4: Boolean = true
scala> b1.hashCode != b2.hashCode res5: Boolean = true scala> b1.toString != b2.toString res6: Boolean = true
Jeśli klasa przypadku dziedziczy metody equals, hashCode lub toString zdefiniowane w klasie innej niż AnyRef, to te wersje również mają pierwszeństwo przed domyślnie generowanymi wersjami.
Plik CaseClassesCD.scala: class C { override def equals(that: Any) = super.equals(that) override def hashCode = super.hashCode override def toString = super.toString } case class D(a:Int, b:String, c:Long) extends C
Klasa przypadku D, z pliku CaseClassesCD.scala, nie definiuje własnych wersji tych metod, ale dziedziczy je z klasy C. Te odziedziczone wersje mają pierwszeństwo przed wersjami domyślnymi.
scala> val d1 = new D(1,"d",2L) d1: D = D@18f9349 scala> val d2 = new D(1,"d",2L) d2: D = D@1956878 scala> d1 != d2 res7: Boolean = true scala> d1.hashCode != d2.hashCode res8: Boolean = true scala> d1.toString != d2.toString res9: Boolean = true