equals, hashCode, toString
Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 35 de 57.
Toda clase hereda toString(), equals() y hashCode() de Any. Las versiones heredadas funcionan según la identidad: toString() proporciona el nombre de la clase y un código hash, y equals() es true únicamente para el mismo objeto. Sobrescribir toString() proporciona a los objetos un texto legible, utilizado por println y las plantillas de cadenas:
class Money(val cents: Int) {
override fun toString() = "$%d.%02d".format(cents / 100, cents % 100)
}Dentro de main:
val price = Money(1250)
println(price)
println("total: ${Money(99)}")Salida:
$12.50
total: $0.99== llama a equals(), mientras que === comprueba si dos referencias apuntan al mismo objeto. Para comparar por valor, sobrescribe equals. Su parámetro es Any?, por lo que primero comprueba el tipo y después compara las propiedades relevantes:
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()
}Dentro de main:
val a = Isbn("978-0-441-17271-9")
val b = Isbn("9780441172719")
println(a == b)
println(a === b)Salida:
true
falseLos objetos que son iguales deben tener códigos hash iguales. HashSet y HashMap buscan las entradas primero mediante hashCode() y solo después llaman a equals(), por lo que sobrescribir equals sin hashCode hace que los objetos iguales parezcan diferentes en ellos. Sobrescribe siempre ambos, calculados a partir de las mismas propiedades:
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"
}Dentro de 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)Salida:
2
trueUna clase de datos genera las tres a partir de las propiedades de su constructor. Escríbelos tú mismo cuando la igualdad deba usar menos propiedades o una forma normalizada, como una dirección de correo electrónico que ignore las mayúsculas y minúsculas:
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>"
}Dentro de main:
val users = listOf(User("Ada@Example.com", "Ada"), User("ada@example.com ", "A. Lovelace"))
println(users.distinct())Salida:
[Ada <ada@example.com>]Desafío
FácilDos productos son iguales cuando sus sku coinciden, sin importar lo que indiquen los demás campos. Sobrescribe equals() y hashCode() en Product usando únicamente sku, y toString() para que un producto se muestre como A1 tea 450. Después completa mergeCatalog(products), que conserva la primera aparición de cada producto en el orden original.
El código proporcionado lee los productos como líneas con el formato sku,name,price y una última línea con un sku que se debe buscar. Imprime cada producto conservado, removed: 2 y A1 in catalog: true, buscando el sku en un HashSet.
Tu código va en Product.kt y Functions.kt. Main.kt contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
fun main() {
// Código de entrada/salida suministrado: déjalo tal como está
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()}")
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesConstructores primariosBloques init y validaciónConstructores secundariosRepaso - Tarjeta de biblioteca4Herencia
Clases abiertas y subclasesSobrescritura de miembrossuper y constructoresClases abstractasRepaso: directorio del personal7Clases especiales
Clases de datosClases enumJerarquías selladasequals, hashCode, toStringRepaso - Rastreador de pedidos2Propiedades y encapsulación
Accesores personalizadosModificadores de visibilidadSetters privadoslazy y lateinitRepaso: cuenta bancaria5Interfaces
Declaración de interfacesMétodos predeterminadosInterfaces múltiplesInterfaces como tiposRepaso: métodos de pago8Genéricos
Funciones genéricasClases genéricasRestricciones de tiposVariancia con in y outRepaso - Cola de prioridad11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Kotlin