코틀린 컴파일러는 equals, hashCode, toString 등과 같이 클래스가 구현해야 하는 메소드를 컴파일 과정에서 자동으로 생성해준다.
클래스를 예시로 들어보자
class Client(val name: String, val postalCode: Int)
기본 제공되는 객체의 문자열 표현은 Client@e9f23b4
같은 방식인데, 이 기본 규칙을 바꾸려면 toString 메소드를 오버라이드해야 한다.
class Client(val name: String, val postalCode: Int) {
override fun toString(): String {
return "Client (name=$name, postalCode=$postalCode)"
}
}
서로 다른 두 객체가 내부에 동일한 데이터를 포함하는 경우 그 둘을 동등한 객체로 간주해야 하는 경우 어떻게 해야 할까? 현재의 Client는 내부 데이터가 동일한 서로 다른 두 객체를 equals로 확인하면 false가 반환된다.
val client1 = Client("A", 1)
val client2 = Client("A", 1)
println(client1 == client2) // false
자바에서는 ==를 원시 타입과 참조 타입을 비교할 때 사용한다. 원시 타입의 경우 ==는 두 피연산자의 값이 같은지 비교한다(동등성(equality)). 반면 참조 타입의 경우 ==는 두 피연산자의 주소가 같은지를 비교한다(참조 비교(reference comparision)). 따라서 자바에서는 두 객체의 동등성을 알려면 equals를 호출해야 한다. equals 대신 ==를 호출하면 문제가 될 수 있다.
Kotlin에서 == 연산자는 내부적으로 equals를 호출해서 객체를 비교한다. 참조 비교를 위해서는 === 연산자를 사용할 수 있다. Kotlin의 ===는 자바에서 객체의 참조를 비교할 때 사용하는 == 연산자와 같다.
이제 equals를 추가한 Client 클래스를 살펴보자
class Client(val name: String, val postalCode: Int) {
override fun toString(): String {
return "Client (name=$name, postalCode=$postalCode)"
}
override fun equals(other: Any?): Boolean {
if (other == null || other !is Client) {
return false
}
return name == other.name && postalCode == other.postalCode
}
}
코틀린의 is 검사는 자바의 instanceof와 같다.
코틀린에서는 override 변경자가 필수여서 other: Any? 대신 other: Client를 파라미터로 입력받는 equals 함수를 작성할 수 없다.
현재 Client는 제대로 동작하지 않는 경우가 있는데, hashCode를 구현하지 않아서 그렇다.
자바에서는 equals를 오버라이드할 때 반드시 hashCode도 함께 오버라이드해야 한다. 그 이유를 알아보자.