Kotlin

코틀린의 Extension 지원

지 슈 2022. 10. 7. 16:26

What is

Extension 

  • 상속이나 디자인 패턴 없이 클래스를 간단하게 확장할 수 있는 방법

(자바에는 확장 기능이 없어서 AOP 같은 관점 지향 프레임워크를 동원해서 사용함.)

+ 자바와 달리 코틀린은 클래스가 기본적으로 기본 상속 변경자가 final 이라서 open 키워드를 달아주지 않으면 상속 불가능하다. 그래서 확장(Extension)을 지원한다.

  • 정적 바인딩된다는 특징

정적 바인딩이란: 컴파일 시간에 구성요소의 성격이 결정되는 것.

 

 

코틀린의 확장 함수(Extension function)

클래스로 대변되는 타입에 함수를 상속관계 없이 추가하는 것.

함수를 마치 이 타입의 메소드(멤버 함수)인 것처럼 호출 가능.

호출 가능한 함수들은 패키지의 멤버 함수이다.

새로운 클래스를 만들지 않아도 되어서 간편하게 사용 가능하다.

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

위 예시는 MutableList<Int> 에 swap 함수를 추가한다.

MutableList<>는 수신자 타입(receiver type)이다: 확장하려는 대상이 되는 타입

swap 은 확장 함수

확장 함수를 만드는 방법:
클래스 이름 .(온점) 함수 이름

 

확장함수는 클래스 안에 들어가지 않는다.

실제로 메서드를 클래스 안에 만드는 것이 아니라 클래스 밖에서 선언되는 것이다. 마치 이 클래스의 멤버 함수인 것처럼.

 

* 단 확장 함수는 수신되는 클래스가 private이나 protected 일 때 사용하지 못함. public 멤버만 사용 가능하다.

(확장 함수는 클래스 밖에서 접근하는 형태이기 때문에)

 

 

코틀린의 확장 프로퍼티(Extension Property)

함수 확장 뿐만 아니라 프로퍼티 확장도 할 수 있다.

프로퍼티, 즉 멤버 변수도 확장 가능.

val <T> List<T>.lastIndex: Int
    get() = size - 1
확장할 때 클래스 안에 멤버를 넣는 것이 아니라서 확장 프로퍼티를 초기화할 수 없다.
getter/setter 를 명시적으로 제공함으로써 초기화와 같은 기능을 사용할 수 있다.

아래와 같은 코드는 에러가 발생한다.

val House.number = 1 // error: initializers are not allowed for extension properties

 

확장 함수 import

확장 함수를 정의해도 프로젝트의 모든 소스코드에서 함수를 사용할 수는 없어서 import 를 해야 한다.

코틀린에서는 개별 함수를 임포트 할 수 있다.

만약 한 클래스 안에 같은 이름의 함수가 둘 이상 있다면 서로 충돌하여 오류가 생긴다.

이 경우, as 키워드를 사용하여 다른 이름으로 바꿔주면 된다.

import ~.common.convertToMileage
import ~.utils.convertToMileage as toMileage

val mileage = 52000
mileage.convertToMileage() //common 패키지의 확장함수
mileage.toMileage() //utils 패키지의 확장함수
//https://0391kjy.tistory.com/18 참고

 

확장 함수의 오버라이드과 오버로드

확장 함수는 오버라이딩 불가능하다. 확장 함수는 클래스 밖에서 선언되기 때문이다.

오버라이딩이란? 상위 클래스의 메서드와 이름과 용례가 같은 함수를 하위 클래스에 재정의하는 것

 

확장 함수는 오버로드 가능하다. 클래스의 메소드와 확장 함수의 이름이 같더라도 매개 변수 타입이 다르면 가능하다.

오버로드란? 같은 클래스나 상속 관계에서 동일한 이름의 메소드 중복 작성.

class Me {
    fun getHeight(height: Int) {
        println("제 키는 ${height}cm 입니다.")
    }
}
 
fun Me.getHeigth(height: Float) {
    println("제 키는 ${height}cm 입니다.")
}
 
fun main() {
    val me = Me()
    me.getHeight(180) // 제 키는 180cm 입니다.
    me.getHeigth(180.3F) // 제 키는 180.3cm 입니다.
}

*humancoding 강의, kotlinlang.org 참고