equals, hashCode, toString
本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 35 课,共 57 课。
每个类都会从 Any 继承 toString()、equals() 和 hashCode()。继承的方法基于对象标识进行操作:toString() 会返回类名和哈希码,而 equals() 只有在对象相同时才为 true。重写 toString() 可以让对象显示为易读的文本,println 和字符串模板会使用这段文本:
class Money(val cents: Int) {
override fun toString() = "$%d.%02d".format(cents / 100, cents % 100)
}在 main 中:
val price = Money(1250)
println(price)
println("total: ${Money(99)}")输出:
$12.50
total: $0.99== 会调用 equals(),而 === 会检查两个引用是否指向同一个对象。要按值比较,请重写 equals。它的参数是 Any?,因此会先检查类型,然后比较相关属性:
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()
}在 main 中:
val a = Isbn("978-0-441-17271-9")
val b = Isbn("9780441172719")
println(a == b)
println(a === b)输出:
true
false相等的对象必须具有相同的哈希码。HashSet 和 HashMap 会先通过 hashCode() 查找条目,然后才调用 equals(),因此只重写 equals 而不重写 hashCode,会让它们认为相等的对象并不相同。始终同时重写这两个方法,并根据相同的属性计算它们的结果:
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"
}在 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)输出:
2
true数据类会根据构造函数属性生成这三个方法。如果相等性判断应使用更少的属性或经过规范化的形式(例如忽略大小写的电子邮件地址),就自己编写这些方法:
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>"
}在 main 中:
val users = listOf(User("Ada@Example.com", "Ada"), User("ada@example.com ", "A. Lovelace"))
println(users.distinct())输出:
[Ada <ada@example.com>]挑战
简单当两个产品的 sku 相同时,它们就是同一个产品,其他字段的值无关紧要。只根据 sku 为 Product 重写 equals() 和 hashCode(),并重写 toString(),让产品打印为 A1 tea 450。然后完成 mergeCatalog(products),按原始顺序保留每个产品的第一次出现。
提供的代码会读取格式为 sku,name,price 的产品数据行,以及最后一行中用于查找的 sku。它会打印所有保留的产品、removed: 2 和 A1 in catalog: true,并在 HashSet 中查找该 sku。
你的代码应写在 Product.kt 和 Functions.kt 中。Main.kt 包含提供的输入/输出代码,不能编辑。
亲手试试
fun main() {
// 提供的输入输出代码:保持原样。
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()}")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Kotlin 在线编辑器