코틀린의 모든 객체는 직 간접적으로 Any 클래스를 상속한다.
그렇기 때문에 Any 클래스의 public open 메서드인 toString(), equals(), hashCode()를 재정의 할 수 있다.
equals(): 두 객체가 구조적으로 동등한가? 에 대한 불리언을 반환하는 메서드hashCode(): 객체 해시코드를 반환하는 메서드toString(): 객체를 문자열로 반환하는 메서드1번이 재정의가 필요한 이유는 지난 포스팅에서 다뤘기 때문에 생략하고 2번 메서드의 재정의가 필요한 이유를 알아보자.
코틀린에서 지원하는 자료구조인 HashSet에 다음과 같은 객체를 넣는다고 해보자.
class Address(
val city: String,
val street: String,
val house: String
) {
override fun equals(other: Any?): Boolean {
if (other !is Address) return false
if (city == other.city && street == other.street && house == other.house) return true
return false
}
}
fun main() {
val addr1 = Address("Seoul", "Mapodaero", "5")
val addr2 = Address("Seoul", "Mapodaero", "5")
val set = HashSet<Address>()
set.add(addr1)
println(addr2 in set) // 구조적으로 같기에 있다고 반환해야하지만... 없다고 판단
println(addr1)
}
HashSet은 원소의 존재 유무를 객체의 해시코드가 존재하는지를 따져 판단한다.
그런데, addr1과 addr2는 구조적으로 동등하지만 해시코드가 달라 addr2가 집합에 없다고 나온다. 이런 문제를 방지하기 위해 hashCode()를 정의해야한다.
// Address 클래스 내 오버라이딩
override fun hashCode(): Int {
// 일반적으로 31을 곱해준다.
var hash = city.hashCode()
hash = 31 * hash + street.hashCode()
hash = 31 * hash + house.hashCode()
return hash
}
기본적인 자료형인 String에 대한 hashCode() 값을 받아 Address의 hashCode()를 재정의하였다.
toString() 메서드는 원래 "해당 객체가 존재하는 패키지 + 객체의 이름 + 해시코드" 를 반환하는 메서드이다.
그러나 위 문자열은 사람이 읽기도 힘들 뿐더러 객체가 어떤 값을 가지고 있는지 알기 힘들다.
toString() 메서드는 사람이 읽기 쉽도록 재정의하면 된다. 예시는 다음과 같다.
override fun toString(): String {
return "$city $street $house"
}