[Kotlin] Data Class의 equals() 알고 쓰자!

HEESTORY·2024년 1월 14일

이 글은 Baeldung Data Classes's equals() Method 을 기반으로 작성되었습니다.

Data class가 제공하는 함수들

데이터 클래스의 각 property에 대해, 컴파일러는 여러 추가적인 함수를 제공한다.

  • equals()
  • hashcode()
  • toString()
  • componentN()
  • copy()

요 아이들을 하나씩 파해져보자. 이번 글에서는 equals()에 대해 알아보자.

equal(): data class의 parameter 값들을 비교한 결과를 리턴.

data class Person(
  val name: String,
)

val person1 = Person("dh")
val person2 = Person("dh")
val person3 = Person("hd")

println(person1.equals(person2))
println(person1.equlas(person3))

print의 결과는 true, false 이다.
(cf. Person이 Data class가 아니라 그냥 class 였다면 false, false가 출력되었을 것이다. Class의 equals()는 인스턴스 자체가 같은지를 비교하기 때문.)

equals() 사용 시 주의할 점

equals()를 사용할 때 주의해야할 점이 두가지가 있다.

첫번째. Data class의 equals()는 data class body 내에 있는 properties가 같은지 까지는 비교해주지 않는다는 것!

data class Person(val name: String){
  var age: Int = 20
}

val person1 = Person("dh")
val person2 = Person("dh")
person1.age = 20
person2.age = 30

println(person1.equals(person2))

print의 결과는 true이다.

data class의 equals()는 primary constructor의 속성들만 비교하기 때문에 body 내에 선언된 age는 같은지 다른지 비교 대상 자체가 아니게 된다. 내부 property들까지 비교하고 싶다면, equals() function의 재정의가 필요하다.

data class Person(val name: String){
  var age: Int = 20
}
  
  override fun equals(other: Any?): Boolean {
    if (other === this) return true
    if (other !is Person) return false
    return this.name == other.name && this.age == other.age
  }
}

val person1 = Person("dh")
val person2 = Person("dh")
person1.age = 20
person2.age = 30

println(person1.equals(person2))

equals를 data class의 parameters, properties에 대해 모두 비교한 결과를 리턴하도록 override하면, print의 결과는 비로소 false가 된다.

두번째. data class의 equals()는 각 parameter type의 equals() function을 이용하여 값을 비교한다는 것!

data class Person(
  val name: String, 
  val initial: CharArray
)

val person1 = Person("dh", charArrayOf('k', 'd', 'h')
val person2 = Person("es", charArrayOf('k', 'e', 's')

println(person1.equals(person2))

print의 결과는 false이다. 왜?! charArray의 equals()는 객체의 주소를 비교하기 때문.
data class의 primary constructor에 있는 parameter라고 무조건 값으로 비교될 것이라고 생각하면 안된다. 해당 parameter data type의 equals()가 어떻게 동작하는지를 알고 equals를 사용해야 한다.

우리가 원하는대로 동작하도록 위 코드를 고친고 싶다면 두가지 방법이 있다.

  • 방법1. 값을 가지고 equals() 연산을 하는 data type으로 바꿔준다.
data class Person(
  val name: String, 
  val initial: List<Char>
)

val person1 = Person("dh", listOf('k', 'd', 'h')
val person2 = Person("es", listOf('k', 'e', 's')

println(person1.equals(person2))
  • 방법2. equals()를 재정의한다.
data class Person(
  val name: String, 
  val initial: CharArray
){
  override fun equals(other: Any?): Boolean {
    if (other === this) return true
    if (other !is Person) return false
    return this.name == other.name && this.initial.contentsEquals(other.age)
  }
}

val person1 = Person("dh", charArrayOf('k', 'd', 'h')
val person2 = Person("es", charArrayOf('k', 'e', 's')

println(person1.equals(person2))

equals()를 사용할 땐 위 두가지를 주의하자!
(+여기서 다루진 않았지만, equals 재정의할 때는 hashcode()도 재정의 해주는 게 좋다. 하나만 재정의하면, equals() 나중에 원하는대로 동작하지 않을 때, 디버깅하기가 어렵다. hashcode() 재정의하는 방법은 hashcode() 편에서 다뤄보도록 하쟈.)

profile
더 나은 내가 되기 위한 공부 기록

0개의 댓글