프로그래밍백엔드 개발자 / 중급 Kotlin 개발자

Kotlin에서 연산자 오버로딩(operator overloading)란 무엇이며, 이를 올바르게 사용하는 방법과 연산자 오버로딩 시 발생할 수 있는 함정은 무엇인가요? 자세한 예시를 제시하고 최선의 실천 방법을 설명하세요.

Hintsage AI 어시스턴트로 면접 통과

답변

Kotlin에서는 키워드 operator를 통해 연산자 오버로딩이 지원됩니다. 이를 통해 사용자 정의 타입에 대해 표준 연산자(+, -, *, [], == 등)의 자체 로직을 정의할 수 있습니다:

  • 이를 위해 필요한 이름으로 메서드를 선언하고 operator 수정자로 마크해야 합니다.
  • 가능한 연산자 오버로딩 목록은 언어에 고정되어 있습니다.

예시:

data class Vec2(val x: Int, val y: Int) { operator fun plus(other: Vec2) = Vec2(x + other.x, y + other.y) } val a = Vec2(1,2) val b = Vec2(2,3) val c = a + b // operator fun plus 호출

주의사항 및 최선의 실천 방법:

  • 예상되는 동작을 유지하세요 (예: ==equals는 일치해야 함).
  • 타입에 대해 명확하지 않은 경우 연산자 구문을 남용하지 마세요.
  • 실제로 타입에 논리적인 연산자만 오버로딩하는 것이 권장됩니다.

함정이 있는 질문

연산자 ==의 오버로딩과 메서드 equals()의 재정의는 어떻게 다릅니까?

답변: Kotlin에서 연산자 ==는 항상 equals() 메서드를 호출합니다 (사전에 null 체크가 있습니다). operator fun equals(other: Any?): Boolean을 정의하면 항상 이 메서드를 사용하게 됩니다. ==equals()가 서로 다르게 작동하게 만들 수는 없습니다.

data class Point(val x: Int, val y: Int) { override operator fun equals(other: Any?): Boolean { ... } } val a = Point(1,2) val b = Point(1,2) println(a == b) // a.equals(b) 호출

역사

명시적인 의미 없이 compareTo 연산자를 오버로딩:

Point 클래스에서 정렬을 사용할 수 있도록 operator fun compareTo를 정의했습니다. 그러나 "더 큼"과 "더 작음"은 명확한 의미가 없었고, 팀의 다양한 멤버가 각기 다른 로직을 작성했습니다. 결과적으로 선택 정렬 과정에서 혼란스러운 버그가 발생했습니다.


역사

양쪽 타입에 대한 연산자의 대칭성을 잊음:

개발자가 operator fun plus(a: Matrix, b: Vector): Matrix를 구현했지만, Vector + Matrix에 대한 작업을 제공하지 않았습니다, 대칭 함수가 구현되지 않았기 때문입니다. 결과적으로 표현식 vector + matrix는 컴파일되지 않았고, 오직 matrix + vector만 작동했습니다. 이로 인해 코드의 여러 부분에서 버그가 발생했습니다.


역사

잘못된 get 연산자 오버로딩:

개발자가 사용자 정의 클래스를 만들면서 operator fun get(index: Int): Foo를 오버로딩했습니다. 경계 체크를 추가하지 않아 존재하지 않는 요소에 접근할 경우 유효하지 않은 필드를 가진 객체를 반환하게 되어 예외를 던지지 않았습니다 — 이로 인해 비즈니스 로직에 "보이지 않는" 오류가 발생했습니다.