본문 바로가기
Kotlin

[Kotlin in Action] 7.2 비교 연산자 오버로딩

by Nhahan 2025. 3. 26.

equals나 comapreTo를 호출해야 하는 자바와 달리 코틀린에서는 == 비교 연산자를 직접 사용할 수 있어서 비교 코드가 equals나 compareTo를 사용한 코드보다 더 간결하며 이해하기 쉽다.

 

7.2.1 동등성 연산자: equals

코틀린은 == 연산자 호출을 equals 메소드 호출로 컴파일 한다.

!= 연산자를 사용하는 식도 equals 호출로 컴파일 된다. ==와 !=는 내부에서 인자가 null인지 검사하므로 다른 연산과 달리 null이 될 수 있는 값에도 적용할 수 있다.

// equals 메소드 구현하기
class Point(val x: Int, val y: Int) {
    override fun equals(obj: Any?): Boolean { // Any에 정의된 메소드를 오버라이딩
        if (obj === this) return true // 최적화: 파라미터가 "this"와 같은 객체인지 검사
        if (obj !is Point) return false // 파라미터 타입 검사
        return obj.x == x && obj.y ==y // Point로 스마트 캐스트해서 x와 y 프로퍼티에 접근
    }
}

equals 함수에는 operator가 아닌, override가 붙어있다. 다른 연산자 오버로딩 관례와 달리 equals는 Any에 정의된 메소드이므로 override가 필요하다(동등성 비교를 모든 코틀린 객체에 대해 적용할 수 있다).

Any의 equals에는 operator가 붙어있지만, 그 메소드를 오버라이드하는 메소드 앞에는 operator를 붙이지 않아도 자동으로 상위 클래스의 operator 지정이 적용된다. 또한 Any에서 상속 받은 equals가 확장 함수보다 우선순위가 높기 때문에 equals를 확장 함수로 정의할 수는 없다는 사실에 유의하자.

 

7.2.2 순서 연산자: compareTo

자바에서 정렬이나 최댓값, 최솟값 등 값을 비교해야 하는 알고리즘에 사용할 클래스는 Comparable 인터페이스를 구현해야 한다. Comparable에 들어있는 compareTo 메소드는 한 객체와 다른 객체의 크기를 비교해 정수로 나타내준다. 하지만 자바에는 이 메소드를 짧게 호출할 수 있는 방법이 없다. < 혹은 > 등의 연산자로는 원시 타입의 값만 비교할 수 있다. 다른 모든 타입의 값에는 element1.compareTo(element2)를 명시적으로 사용해야 한다.

코틀린도 똑같은 Comparable 인터페이스를 지원한다. 게다가 코틀린은 Comparable 인터페이스 안에 있는 compareTo 메소드를 호출하는 관례를 제공한다. 따라서 비교 연산자(<, >, <=, >=)는 comapreTo 호출로 컴파일된다. compareTo가 반환하는 값은 Int다. p1 < p2는 p1.compareTo(p2) < 0과 같다. 다른 비교 연산자도 똑같은 방식으로 작동한다.

 

// compareTo 메소드 구현하기
class Person(
    val firstName: String, val lastName: String
) : Comparable<Person> {
    override fun compareTo(other: Person): Int {
        return compareValuesBy(this, other, Person::lastName, Person::firstName)
    }
}
>>> val p1 = Person("Alice", "Smith")
>>> val p2 = Person("Bob", "Johnson")
>>> println(p1 < p2)
false

여기서 정의한 Person 객체의 Comparable 인터페이스를 코틀린뿐 아니라 자바 쪽의 컬렉션 정렬 메소드 등에도 사용할 수 있다. equals와 마찬가지로 Comparable의 compareTo에도 operator 변경자가 붙어있으므로 하위 클래스의 오버라이딩 함수에 operator를 붙일 필요가 없다.

 

댓글