프로퍼티 선언 Declaring properties
Kotlin 클래스에서 프로퍼티를 만드는 키워드는 두 가지다.
- var : mutable
- val : immutable
Getter and Setter
프로퍼티 선언 문법은 다음과 같다. 코틀린은 getter/setter 기본 구현을 제공한다.
var <propertyName> [: <propertyType>] [= <property_initializer]
[<getter>]
[<setter>]
Kotlin은 이니셜라이저 또는 게터를 통해 추론 가능한 타입이라면 프로퍼티 타입을 생략할 수 있다.
프로퍼티의 커스텀 접근자를 정의할 수 있다. 만약 커스텀 getter를 정의했다면 해당 프로퍼티를 콜할 때마다 커스텀 게터의 값을 반환한다.
val isEmpty : Boolean
get() = this.size == 0
만약 프로퍼티의 커스텀 세터를 정의했다면, 언제든 프로퍼티에 값을 할당할 수 있다.
var stringRepresentation: String
get() = this.toString();
set(value) {
setDataFromString(value) //
}
원한다면 세터의 파라미터 네임을 지정할 수 있지만, 관례적으로 세터 파라미터의 이름은 value
다.
위에서도 말했지만 getter로 타입을 추론할 수 있다면 프로퍼티 타입을 생략할 수 있다.
val isEmpty() get() = this.size == 0;
접근자에 주석을 달거나 가시성을 변경해야 하지만, 기본 구현은 변경할 필요가 없는 경우 본문을 정의하지 않고 접근자를 정의할 수 있다.
val setterVisibility: String = "abc"
private set // 세터는 private하고 기본 구현을 가진다.
val setterWithAnnotion: Any? = null
@Inject set // 세터에 애노테이션 달기
Backing field
Backing Field는 getter/setter에 기본적으로 생성되는 프로퍼티다. Kotlin에서 Class 안의 프로퍼티에 값을 할당할 때 내부적으로 setter가, 값을 불러올 때는 getter가 호출된다.
counter
라는 프로퍼티가 있고, 이에 대한 getter/setter 기본 구현은 아래와 같다.
var counter = 0
get() = field
set(value) {
field = value
// counter = value // StackOverFlow. 실제 이름을 사용하면 setter를 재귀호출
}
게터/세터 모두 counter
가 아닌 field
를 사용한다. 만약 여기서 field 키워드 대신 counter를 사용하면 StackOverFlow를 호출한다. 코틀린은 기본적으로 프로퍼티에 대한 게터, 세터를 가지고 있기 때문에
counter = value
이런 식으로 값을 할당하면 counter의 세터를 재귀적으로 호출하는 셈이다. 이 문제를 해결하기 위해 코틀린에서 field
라는 키워드로 Backing field를 제공하는 것이다.
접근자 중 하나 이상 기본 구현을 사용하거나, 커스텀 접근자가 필드 식별자를 통해 이를 참조하는 경우, 프로퍼티에 대한 backing field가 생성된다.
Complie-time constants
const
modifier가 붙은 변수는 컴파일 타임에 이 변수가 read only속성임을 보장한다. const가 붙은 프로퍼티는 제약 조건이 있다.
- 반드시 top-level에 선언되거나
object
또는companion object
의 멤버여야 한다. - 값이
String
또는 primary type이어야 한다. - custom getter를 가질 수 없다.
Late-initialized 프로퍼티와 변수
일반적으로 non-null 프로퍼티를 선언할 때는 생성자에서 초기화한다. 그러나 그렇지 않은 경우도 있다. 예를 들어 프로퍼티가 DI를 통해 생성되거나, unit test의 setup 메서드에서 생성해야 할 때가 있다. 이런 케이스에서는 non-null 프로퍼티라면, 생성하는 게 불가능하다. 이럴 때 lateinit
modifier를 사용해서 초기화를 뒤로 미룰 수 있다.
class MyTest {
lateinit var subject: TestSubject
@Setup fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method()
}
}
lateinit
를 사용하려면
- top-level 프로퍼티이면서
var
변수여야 한다.
lateinit
프로퍼티를 초기화되지 않은 상태에서 사용하면 초기화되지 않았다는 사실을 명확하게 식별 가능한 예외가 발생한다.
또한 lateinit var
프로퍼티가 이미 초기화되었는지 확인하려면 .isInitialized
를 사용하면 된다.
if (foo::bar.isInitialized)
println(foo.bar)
'Kotlin' 카테고리의 다른 글
kotlin generic variance (0) | 2022.02.27 |
---|---|
[Kotlin] 코틀린이 null을 다루는 방식 ? 연산자와 ?: 엘비스 연산자 (0) | 2021.05.15 |