package kapitel_09 /** * Beispiel aus * * - Algorithmen und Datenstrukturen für Dummies * - von Andreas Gogol-Döring und Thomas Letschert * - Verlag Wiley-VCH; Oktober 2019 * - Kapitel 9, Mengen und ihre Speicherung * * @author A. Gogol-Döring, Th. Letschert */ import scala.collection.mutable.{HashSet => MutableHashSet} import scala.collection.immutable.{HashSet => ImmutableHashSet} object AuD_09_05_RabbitMutableObjectHash_App extends App { /* * Gleiche Objekte den gleichen Hashcode liefern müssen. Der Hashcode von $x$ muss also gleich dem * von $y$ und der von $y$ muss gleich dem von $z$ sein. Gleichzeitig sollte sich der Hashcode von $x$ * und $z$ aber unterscheiden. * Hmm, was denn jetzt? Es empfiehlt sich also, von extravaganten Definitionen der Gleichheit Abstand zu nehmen * und sich an das übliche Schema zu halten. Am besten verwendet man wenn immer möglich finale Case-Klassen * mit unveränderlichen Attributen. * * Die Speicherung von Objekte mit veränderlichen Attributen (Feldern) in Hashtabellen ist grundsätzlich * kritisch zu sehen. Wenn es sich nicht vermeiden lässt, dann es einen Unterschied zwischen ``das Selbe'' * und ``das Gleiche'' und es muss geklärt werden, ob equals die Identität oder die Gleichheit testet. * Nehmen wir das Kaninchen Egon, das im Laufe der Jahre erheblich an Lebenserfahrung und Gewicht gewonnen hat, * aber im Grund immer der Selbe geblieben ist, während es in einer veränderlichen und einer unveränderlichen * Hashtabelle steckt: */ final case class Rabbit(name: String, var weight: Int) val egon = Rabbit("Egon", 3) val rabbits_1: MutableHashSet[Rabbit] = MutableHashSet[Rabbit]() var rabbits_2: ImmutableHashSet[Rabbit] = ImmutableHashSet[Rabbit]() rabbits_1.add(egon) rabbits_2 += egon println(s"rabbits_1.contains(egon): ${rabbits_1.contains(egon)}") // false println(s"rabbits_2.contains(egon): ${rabbits_2.contains(egon)}") // false egon.weight = egon.weight+5 // immer noch drin, aber nicht mehr auffindbar: println(s"rabbits_1.contains(egon): ${rabbits_1.contains(egon)}") // false println(s"rabbits_2.contains(egon): ${rabbits_2.contains(egon)}") // false object Korriguert { /* * Das veränderliche Gewicht sollte nicht in die Gleichheit und die Berechnung des Hashcodes einfließen: */ final case class Rabbit(name: String, var weight: Int) { override def equals(other: Any): Boolean = other match { case that: Rabbit => name == that.name case _ => false } override def hashCode(): Int = { 31 * name.hashCode() } } val egon = Rabbit("Egon", 3) val rabbits_1: MutableHashSet[Rabbit] = MutableHashSet[Rabbit]() var rabbits_2: ImmutableHashSet[Rabbit] = ImmutableHashSet[Rabbit]() def check(): Unit = { rabbits_1.add(egon) rabbits_2 += egon println("\nKorrigiert") println(s"rabbits_1.contains(egon): ${rabbits_1.contains(egon)}") // true println(s"rabbits_2.contains(egon): ${rabbits_2.contains(egon)}") // true egon.weight = egon.weight+5 println(s"rabbits_1.contains(egon): ${rabbits_1.contains(egon)}") // true println(s"rabbits_2.contains(egon): ${rabbits_2.contains(egon)}") // true } } Korriguert.check() }