본문 바로가기
공부/이펙티브코틀린

아이템 40 - equals 의 규약을 지켜라

by 띵커베르 2024. 8. 1.
728x90

Any 에는 다음과 같이 잘 설정된 규약들을 가진 메서드들이 있다

- equals

- hashCode

- toString

 

동등성

코틀린에는 두 가지 종류의 동등성이 있습니다.

  • 구조적 동등성: equals 메서드와 이를 기반으로 만들어진 == 연산자(!= 포함)로 확인하는 동등성
    • a 가 nullable 이 아니라면 a == b 는 a.equals(b)로 변환되고 a 가 nullalbe 이라면 a?.equals(b) ?: (b === null) 로 변환
  • 레퍼런스적 동등성: ===, !==  연산자로 확인하는 동등성
    • 두 피연산자가 같은 객체를 가리키면, true 를 리턴합니다.
data class Person(val name: String, val age: Int) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || javaClass != other.javaClass) return false

        other as Person
        return name == other.name && age == other.age
    }

    override fun hashCode(): Int {
        return Objects.hash(name, age)
    }
}

fun main() {
    val person1 = Person("John", 25)
    val person2 = Person("John", 25)
    val person3 = person1

    println(person1 == person2) // true (구조적 동등성)
    println(person1 === person2) // false (레퍼런스 동등성)
    println(person1 === person3) // true (레퍼런스 동등성)
}

 

 

 

 

 

  • equals 메서드의 규약: equals 메서드는 다음의 다섯 가지 조건을 충족해야 합니다.
    • 반사성: 객체는 자기 자신과 같아야 합니다. a.equals(a)는 항상 true입니다.
    • 대칭성: 두 객체가 서로를 향해 같다고 주장해야 합니다. a.equals(b)가 true이면 b.equals(a)도 true입니다.
    • 추이성: 하나의 객체가 두 번째 객체와 같고, 두 번째 객체가 세 번째 객체와 같다면, 첫 번째 객체는 세 번째 객체와도 같아야 합니다. 즉, a.equals(b)가 true이고 b.equals(c)가 true이면 a.equals(c)도 true입니다.
    • 일관성: 비교 결과는 객체의 상태가 변하지 않는 한 일관되게 유지되어야 합니다. 즉, 여러 번 호출해도 항상 같은 결과를 반환해야 합니다.
    • null-아님: 어떤 객체도 null과 같지 않습니다. a.equals(null)은 항상 false입니다.
  • equals 메서드 구현 시 주의사항:
    • 올바른 타입 확인: 비교하려는 객체의 타입을 확인하고, 잘못된 타입이면 false를 반환합니다.
    • null 검사: 비교 대상 객체가 null인지 확인하고, null이면 false를 반환합니다.
    • 중요한 필드 비교: 객체의 중요한 필드를 비교하여 동등성을 판단합니다.
  • hashCode와의 연관성:
    • equals 메서드를 재정의할 때는 hashCode 메서드도 반드시 재정의해야 합니다. 그렇지 않으면 해시 기반 컬렉션(e.g., HashMap, HashSet)에서 일관된 동작을 보장할 수 없습니다.
    • equals가 true인 두 객체는 동일한 hashCode를 반환해야 합니다.

 

 

재밌는건 책에나와있듯이(URL과 관련된 equals 문제) equals 를 정의할때 동등성이 무언가에 의존한다면 상황에 따라 달라질 수 있기에 조심해야 할듯 하다.

 

 

특별한 이유가 없는 이상, equals 를 직접 구현하지 않는것이 좋다.

(상송을 지원하면서도 완벽한 사용자 정의 equals 함수를 만드는 것은 거의 불가능에 가깝다.)

 

728x90

댓글