equals, hashCode, toString
Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 35 sur 57.
Chaque classe hérite de toString(), equals() et hashCode() de Any. Les versions héritées fonctionnent sur l’identité : toString() donne le nom de la classe et un code de hachage, et equals() vaut true uniquement pour le même objet. Redéfinir toString() fournit aux objets un texte lisible, utilisé par println et les modèles de chaînes :
class Money(val cents: Int) {
override fun toString() = "$%d.%02d".format(cents / 100, cents % 100)
}À l’intérieur de main :
val price = Money(1250)
println(price)
println("total: ${Money(99)}")Résultat :
$12.50
total: $0.99== appelle equals(), tandis que === vérifie si deux références pointent vers le même objet. Pour comparer par valeur, redéfinissez equals. Son paramètre est Any? : la méthode vérifie donc d’abord le type, puis compare les propriétés pertinentes :
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()
}Dans main :
val a = Isbn("978-0-441-17271-9")
val b = Isbn("9780441172719")
println(a == b)
println(a === b)Sortie :
true
falseLes objets qui sont égaux doivent avoir des codes de hachage égaux. HashSet et HashMap recherchent d’abord les entrées avec hashCode(), puis appellent equals(). Ainsi, redéfinir equals sans hashCode fait paraître les objets égaux différents pour ces collections. Redéfinissez toujours les deux, en les calculant à partir des mêmes propriétés :
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"
}Dans 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)Sortie :
2
trueUne classe de données génère les trois à partir de ses propriétés de constructeur. Écrivez-les vous-même lorsque l’égalité doit utiliser moins de propriétés ou une forme normalisée, comme une adresse e-mail qui ignore la casse :
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>"
}À l’intérieur de main :
val users = listOf(User("Ada@Example.com", "Ada"), User("ada@example.com ", "A. Lovelace"))
println(users.distinct())Résultat :
[Ada <ada@example.com>]Défi
FacileDeux produits sont identiques lorsque leur sku correspond, quels que soient les autres champs. Redéfinissez equals() et hashCode() dans Product en vous basant uniquement sur sku, ainsi que toString() afin qu’un produit s’affiche comme A1 tea 450. Complétez ensuite mergeCatalog(products), qui conserve la première occurrence de chaque produit dans l’ordre d’origine.
Le code fourni lit les produits sous forme de lignes sku,name,price, ainsi qu’une dernière ligne contenant un sku à rechercher. Il affiche chaque produit conservé, removed: 2 et A1 in catalog: true, en recherchant le sku dans un HashSet.
Votre code doit être placé dans Product.kt et Functions.kt. Main.kt contient le code fourni pour les entrées et sorties et ne peut pas être modifié.
Essayez vous-même
fun main() {
// Code d'entrée/sortie fourni : le laisser tel quel
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()}")
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesConstructeurs primairesBlocs init et validationConstructeurs secondairesRécapitulatif - Carte de bibliothèque4Héritage
Classes ouvertes et sous-classesRedéfinition des membressuper et constructeursClasses abstraitesRécapitulatif – Annuaire du personnel7Classes spéciales
Classes de donnéesClasses EnumHiérarchies scelléesequals, hashCode, toStringRécapitulatif - Suivi des commandes2Propriétés et encapsulation
Accesseurs personnalisésModificateurs de visibilitéSetters privéslazy et lateinitRécapitulatif - Compte bancaire5Interfaces
Déclarer des interfacesMéthodes par défautInterfaces multiplesInterfaces en tant que typesRécapitulatif - Méthodes de paiement8Génériques
Fonctions génériquesClasses génériquesContraintes de typeVariance avec in et outRécapitulatif - File de priorité11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Playground Kotlin