equals, hashCode, toString
Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 35 z 57.
Każda klasa dziedziczy toString(), equals() i hashCode() z Any. Dziedziczone wersje działają na podstawie tożsamości: toString() zwraca nazwę klasy i kod skrótu, a equals() ma wartość true tylko dla tego samego obiektu. Nadpisanie toString() sprawia, że obiekty mają czytelny tekst, używany przez println i szablony tekstowe:
class Money(val cents: Int) {
override fun toString() = "$%d.%02d".format(cents / 100, cents % 100)
}Wewnątrz main:
val price = Money(1250)
println(price)
println("total: ${Money(99)}")Wynik:
$12.50
total: $0.99== wywołuje equals(), natomiast === sprawdza, czy dwa odwołania wskazują na ten sam obiekt. Aby porównywać według wartości, nadpisz equals. Jego parametr ma typ Any?, więc najpierw sprawdza typ, a następnie porównuje odpowiednie właściwości:
class Isbn(code: String) {
val digits = code.filter { it.isDigit() }
override fun equals(other: Any?) = other is Isbn && other.digits == digits
override fun hashCode() = digits.hashCode()
}Wewnątrz main:
val a = Isbn("978-0-441-17271-9")
val b = Isbn("9780441172719")
println(a == b)
println(a === b)Wynik:
true
falseRówne obiekty muszą mieć równe kody skrótu. HashSet i HashMap najpierw wyszukują wpisy za pomocą hashCode(), a dopiero potem wywołują equals(), więc nadpisanie equals bez hashCode sprawia, że równe obiekty wyglądają dla nich na różne. Zawsze nadpisuj obie metody, obliczając ich wyniki na podstawie tych samych właściwości:
class Isbn(code: String) {
val digits = code.filter { it.isDigit() }
override fun equals(other: Any?) = other is Isbn && other.digits == digits
override fun hashCode() = digits.hashCode()
override fun toString() = "ISBN $digits"
}Wewnątrz main:
val shelf = hashSetOf(Isbn("978-0-441-17271-9"), Isbn("9780441172719"), Isbn("0-14-143951-3"))
println(shelf.size)
println(Isbn("9780441172719") in shelf)Wynik:
2
trueKlasa danych generuje wszystkie trzy na podstawie swoich właściwości konstruktora. Zapisz je samodzielnie, gdy równość powinna uwzględniać mniej właściwości lub ich znormalizowaną postać, na przykład adres e-mail ignorujący wielkość liter:
class User(val email: String, val name: String) {
private val key = email.trim().lowercase()
override fun equals(other: Any?) = other is User && other.key == key
override fun hashCode() = key.hashCode()
override fun toString() = "$name <$key>"
}Wewnątrz main:
val users = listOf(User("Ada@Example.com", "Ada"), User("ada@example.com ", "A. Lovelace"))
println(users.distinct())Wynik:
[Ada <ada@example.com>]Wyzwanie
ŁatwyDwa produkty są takie same, gdy ich sku jest zgodne, niezależnie od wartości pozostałych pól. Nadpisz equals() i hashCode() w Product, opierając je wyłącznie na sku, oraz toString(), aby produkt był wyświetlany jako A1 tea 450. Następnie uzupełnij mergeCatalog(products), które zachowuje pierwsze wystąpienie każdego produktu w pierwotnej kolejności.
Dostarczony kod odczytuje produkty z wierszy w formacie sku,name,price oraz z ostatniego wiersza zawierającego sku do wyszukania. Wyświetla każdy zachowany produkt, removed: 2 i A1 in catalog: true, wyszukując sku w HashSet.
Twój kod umieść w plikach Product.kt i Functions.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
fun main() {
// Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
val input = generateSequence(::readLine).toList()
val products = input.dropLast(1).map { line ->
val (sku, name, price) = line.split(",")
Product(sku, name, price.toInt())
}
val kept = mergeCatalog(products)
for (p in kept) println(p)
println("removed: ${products.size - kept.size}")
val probe = Product(input.last(), "?", 0)
println("${input.last()} in catalog: ${probe in kept.toHashSet()}")
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Klasy i obiekty
Praca z plikamiDefiniowanie klasKonstruktory główneBloki init i walidacjaKonstruktory dodatkowePodsumowanie — karta biblioteczna4Dziedziczenie
Klasy otwarte i podklasyNadpisywanie składowychsuper i konstruktoryKlasy abstrakcyjnePodsumowanie – katalog pracowników7Klasy specjalne
Klasy danychKlasy wyliczenioweHierarchie zapieczętowaneequals, hashCode, toStringPodsumowanie — śledzenie zamówień10Wzorce projektowe, część 2
Delegowanie za pomocą byWzorzec dekoratoraWzorzec budowniczegoWzorzec stanu2Właściwości i hermetyzacja
Własne akcesoryModyfikatory widocznościPrywatne setterylazy i lateinitPowtórka – konto bankowe5Interfejsy
Deklarowanie interfejsówMetody domyślneWiele interfejsówInterfejsy jako typyPowtórzenie – metody płatności8Typy generyczne
Funkcje generyczneKlasy generyczneOgraniczenia typówKowariancja i kontrawariancja: in i outPodsumowanie — kolejka priorytetowa11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książekPoćwicz samodzielnie: Edytor online Kotlin