본문 바로가기
발전로그/책장로그-개발

kotlin in action 03 (3.3)

by 4lleycat 2022. 2. 16.

3.3 메소드를 다른 클래스에 추가: 확장 함수와 확장 프로퍼티

- 확장함수

package strings

// 문자열의 마지막 문자 반환
// 추가하려는 함수이름 앞에 확장하고자 하는 클래스(수신객체타입)의 이름을 붙이면 된다
//fun String.lastChar(): Char = this.get(this.length-1)

fun String.lastChar(): Char = get(length-1) //this 생략 가능

--------------------
// 수신객체 타입 : String
// 수신객체 : "kotlin"
fun main() {
    println("kotlin".lastChar())
}
>>>>>>>>>>>>
n
  • 확장함수
    • 기존 자바 코드와 코틀린 코드를 자연스럽게 통합을 목표로 한다
    • 기존 자바 API를 코틀린으로 재작성 하지 않고도 여러 기능을 사용가능?!
    • 어떤 클래스의 멤버 메소드처럼 호출할 수 있지만 클래스 밖에 위치한다
      • 위 예제처럼 String 클래스에 새로운 메소드를 추가
    • JVM 언어면 가능하다
    • 확장함수는 클래스안에 정의된 메소드와 달라서 수신객체 클래스의 private,protected 멤버를 사용할 수 없다.(캡슐화 유지)

3.3.1 임포트와 확장 함수

// 확장함수도 패키지를 import 해야한다
// 같은 이름의 함수 충돌 방지
// as 로 클래스,함수이름 재정의 가능
import strings.lastChar as last

fun main() {
    println("kotlin".lastChar())
}

3.3.2 자바에서 확장 함수 호출

// java에서 호출
// 패키지 파일명.확장함수
lastChar = strings.lastChar("Java")

 

3.3.3 확장 함수로 유틸리티 함수 정의

package strings

//Collection<T> 확장 함수 선언
fun <T> Collection<T>.joinToStringExtension(
    separator: String = ", ",
    prefix: String = "",
    postFix: String = ""
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in this.withIndex()) { // 수신객체 Collection<T> 타입 컬랙션 객체
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postFix)
    return result.toString()
}

// 구체적인 타입을 지엉하면 객체에 리스트로는 호출불가
fun Collection<String>.joinToTypeString(
    separator: String = ", ",
    prefix: String = "",
    postFix: String = ""
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in this.withIndex()) { // 수신객체 Collection<T> 타입 컬랙션 객체
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postFix)
    return result.toString()
}
---------------------------------

import strings.joinToStringExtension
import strings.joinToTypeString

fun main() {
    val list = arrayListOf(1, 2, 3)
    val strList = arrayListOf("a", "b", "c")
    println(list.joinToStringExtension(prefix = "[", postFix = "]"))
    println(strList.joinToTypeString())
}
>>>>>>>>>>>>>>>>>.
[1, 2, 3]
a, b, c

3.3.4 확장함수는 오버라이드 할 수 없다

open class View {
    open fun click() = println("View Clicked")
}


open class Button: View() {
    override fun click() = println("Button Clicked")
}

fun View.showOff() = println("i am View")
fun Button.showOff() = println("i am Button")
fun main() {
    val view: View = Button() // view 에지정된 값의 실제 타입에따라 호출메소드가 결정된다.
    view.click()
    
    // "i am View" showOff 확장함수는 실제 가르키는 Button 객체 에서 재정의 되지 못한다
    // View 수신객체의 값을 반환
    // 확장함수는 정적이다.
    view.showOff() 
}
  • 이름과 시그니처가 같은 메서드(=확장함수)와 멤버메서드 호출시 멤버메서드가 우선순위를 갖는다

3.3.5 확장 프로퍼티

// 확장 프로퍼티 선언
val String.lastChar: Char
    get() = get(length - 1)

var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value:Char) {
        this.setCharAt(length - 1, value) // this 생략가능
    }


fun main() {
   println("kotlin".lastChar)
   val sb = StringBuilder("kotlin?")
   sb.lastChar = '!' //TODO single quote??
   println(sb)
}
  • 일반적인 프로퍼티와 같지만 확장함수처럼 수신객체를 같는다.