자바에서는 연산자 오버로딩을 허용하지 않는다. 원시 타입에 한해서만 산술 연산자를 사용할 수 있었고 예외적으로 String 클래스에 대해 + 연산자를 사용할 수 있었다. 하지만 코틀린을 이를 허용한다. 연산자 오버로딩은 클래스 메소드에 operator 키워드를 붙혀 만든다. 또는 확장함수를 통해 정의하는 것도 가능하다. 이 때 연산자를 새로 만들 수는 없고 코틀린에서 지정한 연산자만 오버로딩할 수 있다.
식 | 함수 이름 |
---|---|
a * b | times |
a / b | div |
a % b | mod(1.1부터 rem) |
a + b | plus |
a + b | minus |
산술 연산자 오버로딩의 위의 5개 연산자에 한에서 가능하다.
data class Point(val x: Int, val y: Int){
operator fun plus(other: Point) = Point(x + other.x, y + ohter.y)
operator fun times(scale: Double) = Point((x * scale).toInt(), (y * scale).toInt())
}
val p = Point(10, 15)
println(p + Point(-10, -15) // Point(x = 0, y = 0) 출력
println(p * 1.5) // Point(x = 15, y = 22) 출력
연산자 오버로딩을 했다고 해서 코틀린에서 교환법칙을 자동으로 지원하지는 않는다. 만약 위의 예제에서 곱셉의 교환법칙을 지원하기 위해서는 Double 클래스에 아래와 같이 연산자를 오버로딩해야한다.
operator fun Double.times(p: Point) = Point((this * p.x).toInt(), (this * p.y).toInt())
+=, -= 등의 연산과 대입을 동시에 수행하는 연산자를 복합 대입 연산자라고 한다. += 은 plusAsign 함수를 정의하여 오버로딩 할 수 있다. 나머지 복합 대입 연산자의 이름은 산술 연산자 이름에 Asign을 붙여주면 된다.
이런 연산자는 주로 참조를 변경하는 것이 아닌 변경 가능한 객체 내부의 값을 변경하기 위함이다. 예를들어 MutableList의 += 은 새로운 원소를 리스트에 집어 넣는다.
operator fun <T> MutableCollection<T>.plusAssign(element: T){
this.add(element)
}
어떤 클래스가 +=과 +의 연산자 오버로딩이 정의되어 있고 +=에 + 연산이 가능한 경우 컴파일러는 에러를 발생시킨다.
a += b
a = a.plus(b)
a.plusAsign(b)
plus와 plusAsign은 동작하는 방식이 완전히 다른다. plus는 참조를 변경하지만 plusAsign은 참조를 변경하지 않고 내부 값을 변경한다.
따라서 산술 연산자 오버로딩과 복합 대입 연산자들 동시에 정의하지 않는게 좋다.
식 | 함수 이름 |
---|---|
+a | unaryPlus |
-a | unaryMinus |
!a | not |
++a, a++ | inc |
--a, a-- | dec |
단항 연산자 오버로딩도 이항 연산자와 마찬가지로 할 수 있다.
자바에서는 객체에 대한 비교 연산자를 사용할 수 없었다. equals나 compareTo를 호출하여 비교 연산을 수행했다. 하지만 코틀린은 비교 연산에 대한 오버로딩을 지원한다.
비교가 필요한 알고리즘에 사용할 클래스는 Comparable 인터페이스를 구현해야한다. 코틀린에서는 Comparable 인터페이스의 compareTo 메소드가 구현되어 있다면 순서 연산자(<, >, >=, <=)를 이용한 비교가 가능하다.
연산자 오버로딩이지만 Comparable 인터페이스에 operator 식별자가 선언되어 있으므로 오버라이드 할 때 operator 식별자를 붙일 필요는 없다.