07-3 연산자 오버로딩
코틀린에서 특정 연산자의 역할을 함수로 정의하고 있습니다. 이를 일종의 협약(Convension)이라고 하는데 수학에서 곱하기 연산이 더하기 연산보다 우선하듯이 연산자 역시 우선순위(Precedence)를 갖고 있습니다.
우선순위 | 분류 | 심볼 |
높음 낮음 |
접미사(Postfix) | ++, --, ., ?., ? |
접두사(Prefix) | -, ++, --, !, 라벨선언(이름@) | |
오른쪽 형식(Type RHS)` | :, as, as? | |
배수(Multiplicative) | *, /, % | |
첨가(Additive) | +, - | |
범위(Range) | .. | |
중위 함수(Infix Function) | SimpleName | |
엘비스(Elvis) | ?: | |
이름 검사(Name Checks) | in, !in, is, !is | |
비교(Comparison) | >, <, >= , <= | |
동등성(Equality) | ==, != | |
결합(Conjunction) | && | |
분리(Disjunction) | || | |
할당(Assignment) | =, +=, -=, *=, /=, %= |
연산자의 작동 방식
연산자를 사용하면 관련된 멤버 메서드를 호출하는 것과 같습니다. :) 예를 들여 a + b는 a.plus(b)라는 함수가 내부적으로 호출되는 것입니다.
코틀린 표준 라이브러리에서 Primitives.kt를 살펴보면 operator 키워드를 사용해 plus()함수가 다양한 자료형으로 선언되어 있는 것을 할 수 있습니다.
+ 연산자의 오버로딩
package chapter_07.chapter_07_3
class Point(var x: Int = 0, var y: Int = 10) {
// plus() 함수의 연산자 오버로딩
operator fun plus(p: Point) : Point {
return Point(x + p.x, y + p.y)
}
}
fun main() {
val p1 = Point(3, -8)
val p2 = Point(2, 9)
var point = Point()
point = p1 + p2 // Point 객체의 + 연산이 가능하게 됨.
println("point = (${point.x}, ${point.y})")
}
/*
결과 :
point = (5, 1)
point = (4, 0)
*/
Point 클래스를 만들고 +연산자를 오버로딩했습니다. 그 객체를 서로 + 연산자를 이용해 좌표 값에 x, y를 더해 새로운 객체에 할당했습니다.
증감 연산자
package chapter_07.chapter_07_3
class Point2(var x: Int = 0, var y: Int = 10) {
// 증감연산자 오버로딩
operator fun dec() = Point2(--x, --y)
}
fun main() {
var point = Point2()
--point // --연산자
println("point = (${point.x}, ${point.y})")
}
/*
결과 :
point = (-1, 9)
*/
--감소 연산자가 정의되었습니다.
호출 연산자
class Point3(var x: Int = 0, var y: Int = 10) {
// 호출 연산자 오버로딩
operator fun invoke(value: String) = println(value)
}
fun main() {
var point = Point3()
// invoke는 생략 할 수 있음.
point.invoke("invoke : Do something for me!")
point("Skip invoke : Do something for me!")
}
/*
결과 :
invoke : Do something for me!
Skip invoke : Do something for me!
*/
호출 연산자는 함수 호출을 돕는데 사용합니다. 소스 코드를 보면 Point3클래스를 통해 새엇앟ㄴ 객체 point라는 이름만으로 접근해 사용할 수 있습니다. 원래는 point.invoke("...") 형태로 호출되어야 하지만 invoke를 생략하고 객체 이름만 작성해서 코드를 읽기 쉬워집니다.
val sum = { a, b -> a + b }
sum.invoke(3, 7)
sum(3, 7) // 위와 동일 식
인덱스 접근 연산자
package chapter_07.chapter_07_3
class Point4(var x: Int = 0, var y: Int = 10) {
val a = arrayOf(1,2,3,4)
}
fun main() {
var point = Point4()
// setter -> [ ]연산자로 입력.
// 1, 2, 3, 4... -> 1, 2, 3, 13
point.a.set(3, 13)
point.a[3] = 13
// getter -> [ ]연산자로 출력.
println("${point.a.get(3)}")
println("${point.a[3]}")
}
/*
결과 :
13
13
*/
인덱스 접근 연산자는 게터/세터를 다루기 위한 대괄호([]) 연산자를 제공합니다.
단일 연산자
package chapter_07.chapter_07_3
data class Point5(var x: Int, var y: Int)
// 단일 연산자 오버로딩
operator fun Point5.unaryMinus() = Point5(-x, -y)
fun main() {
var point = Point5(10, 20)
println(-point)
}
/*
결과 :
Point5(x=-10, y=-20)
*/
확장 함수와 같은 기법으로 Point클래스에 연산자 메서드를 정의했습니다.
범위 연산자
package chapter_07.chapter_07_3
fun main() {
val arr = arrayOf(1,2,3,4,5,6,7,8,9,0)
val i = 1
if(i in 1..10){ // 1 <= i && i >= 1과 동일
println(i)
}
println(1 in 1..10) // 1은 범위에 있음.
println(arr.contains(10)) // 10은 범위에 없음
}
/*
결과 :
1
true
false
*/
in 연산자는 특정 객체를 반복하기 위해 반복문에 사용하거나 범위 연산자와 함께 포함 여부를 판단할 수 있습니다:)
따라서 이 연산자를 오버로딩하려면 contains()메서드를 이용할 수 있습니다. !in 형식은 반대의 경우로 범위에 없는 경우를 가리킵니다. -> ex) (a !in b)식과 (!b.contains(a))은 같은식!
대입 연산자
package chapter_07.chapter_07_3
class Point7(var x: Int = 0, var y: Int = 10) {
}
fun main() {
val point = Point7()
var result: Int = 0
var t: Int = 1
result += point.y
// 결과 : 10 = 0 + 10을 result에 대입
//>>>
}
동등성 연산자
package chapter_07.chapter_07_3
class Point8(var x: Int = 0, var y: Int = 10) {
}
fun main() {
val point = Point()
val a = 10
// a와 10을 비교한 결과 출력 true
println(a == point.y)
// 같은식
var result: Int? = null
println(a?.equals(point.y))
}
/*
결과 :
true
true
*/
동등성 연산자는 두 객체의 값의 동등성을 판별합니다. ==, !=는 둘 다 equals()로 변경되어 동작하는데 위와 같은 판단문이 사용되면 인자가 null이어도 동작하도록 되어 있습니다. 따라서 a와 b가 둘 다 null이면 true를 반환합니다. euqals는 Any안에 operator 키워드가 붙어서 구현되어 있기 때문에 하위 클래스에서는 override 키워드를 사용해서 ==와 치환할 수 있습니다. 또한 이런 특이점 때문에 equals는 확장 함수로 구현할 수 없습니다.
(===, !==와 같은 값, 자료형을 비교하는 연산자는 오버로딩 할 수 없습니다)
비교 연산자
package chapter_07.chapter_07_3
class Point9(var x: Int = 0, var y: Int = 10) {
}
fun main() {
val point = Point9()
val a = 10
// y와 a가 같으므로 false
println(a < point.y)
// 같은식
println(a.compareTo(point.y))
}
/*
결과 :
false
false
*/
마무리 문제
01. 위임을 통해 메서드에 접근하는 코드가 있습니다.
interface A {
fun functionA() { }
}
interface B {
fun functionB() { }
}
class DelegatedC(a: A, b: B): ________ {
fun functionC() {
functionA()
functionB()
}
}
정답 : A by a, B by b
02. 데이터 전달을 위해 사용하는 클래스는 ____ 키워드를 사용하여 정의하면
toString()이나 equals()와 같은 메서드가 자동으로 생성됩니다.
정답 : data
// 03. 다음은 내부의 클래스에서 바깥 클래스의 멤버에 접근하는 코드입니다.
class Outer(val name: String) {
private val origin = "hello"
________class MyClass(val from: String) {
fun getInfo() = "${name} says $origin from ${from}"
}
}
정답 : Inner
이상 마무리하겠습니다. :)
'책 요약하기 > Do it! 코틀린 프로그래밍' 카테고리의 다른 글
#07-2. 애노테이션 클래스 2021-05-16 (0) | 2021.05.16 |
---|---|
#07-2. 데이터 클래스와 기타 클래스 2021-05-15 (0) | 2021.05.15 |
#07-1. 추상 클래스와 인터페이스 2021-05-08 (0) | 2021.05.08 |
#06. 프로퍼티와 초기화 2021-05-02 (0) | 2021.05.02 |
#05-2. super와 this의 참조, 정보 은닉 캡슐화, 클래스와 클래스의 관계 2021-04-27 (0) | 2021.04.27 |