코틀린의 위임 프로퍼티(Delegated Properties)
코틀린의 위임 프로퍼티(Delegated Properties)
Kotlin의 위임 프로퍼티(delegated properties)를 사용하면 프로퍼티의 getter와 setter 로직을 by 키워드를 통해 별도의 위임 객체(delegate object)에 맡길 수 있습니다. 컴파일러는 프로퍼티 접근을 위임 객체의 getValue()와 setValue() 연산자 호출로 변환하므로, 저장, 유효성 검증, 계산 로직 등을 추출하여 서로 관련 없는 클래스에서도 재사용할 수 있습니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
- Kotlin 컴파일러가 위임 프로퍼티를
getValue()와setValue()호출로 어떻게 변환하는지 설명할 수 있습니다. lazy위임의 동작 방식과 스레드 안전성(thread safety) 옵션을 이해할 수 있습니다.Delegates.observable과Delegates.vetoable을 활용하여 변경 추적 및 유효성 검증을 구현할 수 있습니다.Map을 활용한 위임으로 동적 프로퍼티 해석(resolution)을 수행할 수 있습니다.ReadOnlyProperty또는ReadWriteProperty인터페이스를 구현하여 커스텀 위임을 직접 작성할 수 있습니다.
위임 프로퍼티의 컴파일러 변환
위임 프로퍼티를 선언하면, 컴파일러는 위임 객체를 보관하는 숨겨진 필드를 생성하고 모든 프로퍼티 접근을 해당 위임 객체를 통해 호출하도록 재작성합니다.
class Example {
var text: String by SomeDelegate()
}
컴파일러는 위 코드를 대략 다음과 같이 변환합니다.
class Example {
private val text$delegate = SomeDelegate()
var text: String
get() = text$delegate.getValue(this, ::text)
set(value) {
text$delegate.setValue(this, ::text, value)
}
}
위임 객체는 특정 시그니처를 갖는 getValue()를 반드시 제공해야 하며, 가변 프로퍼티인 경우 setValue()도 함께 제공해야 합니다. 첫 번째 매개변수는 프로퍼티 소유자(thisRef)이고, 두 번째는 프로퍼티 메타데이터를 나타내는 KProperty<*>입니다. Kotlin 표준 라이브러리에서는 이 계약(contract)을 공식화하기 위해 ReadOnlyProperty와 ReadWriteProperty 인터페이스를 제공합니다. 이처럼 컴파일러가 생성하는 코드 구조를 이해해 두면, 면접에서 위임 프로퍼티의 내부 동작을 명확하게 설명하실 수 있습니다.
지연 초기화(Lazy Initialization)
lazy 위임은 첫 번째 프로퍼티 접근 시점까지 계산을 지연시키고, 그 결과를 캐싱하여 이후 읽기 시에 재사용합니다. 값을 생성하는 람다를 인자로 받습니다.
val expensiveResult: String by lazy {
println("Computing...")
buildExpensiveString()
}
첫 번째 접근 시 람다가 실행되어 결과를 저장하고 반환합니다. 이후 접근에서는 람다를 다시 실행하지 않고 캐싱된 값을 바로 반환합니다. 기본적으로 lazy는 LazyThreadSafetyMode.SYNCHRONIZED를 사용하므로 여러 스레드에서 안전하게 접근할 수 있지만, 초기화가 완료될 때까지 매 읽기마다 동기화 비용이 발생합니다.