equals, hashCode, toString
Coddy Kotlin 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 35번째.
모든 클래스는 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가 일치하면 두 제품은 동일합니다. Product에서 equals()와 hashCode()를 sku만 기준으로 재정의하고, 제품이 A1 tea 450과 같이 출력되도록 toString()도 재정의하세요. 그런 다음 원래 순서대로 각 제품의 첫 번째 출현만 유지하는 mergeCatalog(products)를 완성하세요.
제공된 코드는 제품을 sku,name,price 형식의 줄과 조회할 sku가 포함된 마지막 줄로 읽습니다. 유지된 모든 제품과 removed: 2, 그리고 HashSet에서 sku를 조회한 결과인 A1 in catalog: true를 출력합니다.
코드는 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 플레이그라운드