KotlinInAction/연산자 오버로딩과 기타 관례

비교 연산자 오버로딩

webmaster 2022. 8. 8. 23:38
728x90

equals(동등성 연산자)

코틀린은 == 연산자 호출을 equals 메서드 호출로 컴파일한다. 사실 이는 특별한 경우가 아닌 여러 관례를 적용한 것에 불과하다

!= 연산자를 사용하는 식도 equals 호출로 컴파일되며, 비교 결과를 뒤집은 값을 결과 값으로 사용한다.

!=, == 모두 내부에서 인자가 널인지 검사하므로 다른 연산과 달리 널이 될 수 있는 값에도 적용할 수 있으며, 널이 아닐 경우에만 a.equals(b)를 호출하게 된다.

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 프로퍼티에 접근한다
    }
}
fun main(args: Array<String>) {
    println(Point(10, 20) == Point(10, 20))
    println(Point(10, 20) != Point(5, 5))
    println(null == Point(1, 2))
}
  • 식별자 비교 연산자(===)를 통해 equals의 파라미터가 수신 객체와 같은지 살펴본다.
    • 자바의 == 연산자와 같다(두 피연산자가 서로 같은 객체를 가리키는지 비교한다)
    • === 같은 식별자 비교 연산자는 오버로딩 할 수 없다
  • equals 함수에는 override 가 붙어 있고 다른 연산자 오버로딩 관례와 달리 equals는 Any에 정의된 메서드라 override가 필요하다
  • Any의 equals에는 operator가 붙어있지만, 그 메서드를 오버라이드 하는 하위 클래스 메서드 앞에는 operator 변경자를 붙이지 않아도 자동으로 상위 클래스의 operator 지정이 적용된다.
  • Any에서 상속받은 equals가 확장 함수보다 우선순위가 높기 때문에 equals를 확장 함수로 정의할 수 없다

compareTo(순서 연산자)

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

코틀린에서는 똑같은 Comparable 인터페이스를 지원한다. 또한 인터페이스에 있는 compareTo 메서드를 호출하는 관례를 제공하여 비교 연산자(>, <, <=,>=)는 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)
    }
}
fun main(args: Array<String>) {
    val p1 = Person("Alice", "Smith")
    val p2 = Person("Bob", "Johnson")
    println(p1 < p2)
}
  • Person 객체의 Comparable 인터페이스를 코틀린뿐만 아니라 자바 쪽의 컬렉션 정렬 메서드에서도 사용할 수 있다
  • Comparable에 compareTo 메서드에도 operator 변경자가 붙어 있으므로 하위 클래스의 오버 라이딩 함수에 붙일 필요 없다
  • compareValuesBy이라는 코틀린 표준 라이브러리 함수를 통해 compareTo를 쉽고 간결하게 정의한다.
    • compareValuesBy은 첫 번째 비교 함수에 두 객체를 넘겨 두 객체가 같이 않다는 결과가 나오면 그 결과를 즉시 반환하고 같다면 두 번째 비교 함수를 통해 두 객체를 비교한다.
    • 두 객체의 대소를 알려주는 0이 아닌 값이 처음 나올 때까지 인자로 받은 함수를 차례로 호출해 비교하며, 모든 함수가 0을 반환하면 0을 반환한다.
    • 필드를 직접 비교하면 코드는 좀 더 복잡해지지만 성능은 더 좋아진다

 

728x90