선언
•
var 키워드를 사용하여 변경 가능한 프로퍼티를 선언할 수 있다.
•
val 키워드를 사용하여 읽기 전용 프로퍼티를 선언할 수 있다.
class Address {
var name: String = "Holmes, Sherlock"
var street: String = "Baker"
var city: String = "London"
var state: String? = null
var zip: String = "123456"
}
Kotlin
복사
•
간단하게 프로퍼티 이름을 가리켜서 사용할 수 있다.
fun copyAddress(address: Address): Address {
val result = Address() // there's no 'new' keyword in Kotlin
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}
Kotlin
복사
Getter와 Setter
•
변경 가능한 프로퍼티를 선언하는 문법
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
Kotlin
복사
•
초기화자, getter, setter는 선택사항이다.
•
만약 초기화자 혹은 getter의 반환 타입으로 타입을 추론할 수 있다면 프로퍼티 타입은 선택사항이다.
var initialized = 1 // has type Int, default getter and setter
// var allByDefault // ERROR: explicit initializer required, default getter and setter implied
Kotlin
복사
•
읽기 전용 프로퍼티를 선언하는 문법
•
setter를 허용하지 않는다.
val simple: Int? // has type Int, default getter, must be initialized in constructor
val inferredType = 1 // has type Int and a default getter
Kotlin
복사
•
프로퍼티가 호출될 떄마다 실행되는 custom getter를 선언할 수 있다.
•
custom getter의 반환 타입을 통해 타입 추론이 가능하다면 프로퍼티의 타입을 생략할 수 있다.
class Rectangle(val width: Int, val height: Int) {
val area: Int // property type is optional since it can be inferred from the getter's return type
get() = this.width * this.height
}
Kotlin
복사
•
프로퍼티에 값을 할당할 때마다 실행되는 (초기화는 예외) custom setter를 선언할 수 있다.
•
관례적으로 setter 파라미터의 이름은 value를 사용한다.
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // parses the string and assigns values to other properties
}
Kotlin
복사
•
접근자에 주석을 달거나 명시적으로 변경해야하지만 기본 구현을 변경하고 싶지 않다면 구현부를 정의하지 않고 접근자를 정의할 수 있다.
var setterVisibility: String = "abc"
private set // the setter is private and has the default implementation
var setterWithAnnotation: Any? = null
@Inject set // annotate the setter with Inject
Kotlin
복사
백킹 필드
•
Kotlin에서 필드는 직접 선언할 수 없고 값을 메모리에 저장하기 위한 프로퍼티의 일부로만 사용된다.
•
프로퍼티에 백킹 필드가 필요할 때 자동으로 제공하며 프로퍼티의 접근자에서만 field 식별자를 사용하여 참조할 수 있다.
var counter = 0 // 초기화가 백킹 필드에 직접 값을 할당합니다.
set(value) {
if (value >= 0)
field = value
// counter = value // ERROR StackOverflow: 'counter'라는 실제 이름을 사용하면 setter가 재귀적으로 호출됩니다.
}
Kotlin
복사
•
백킹 필드는 기본 구현을 사용하는 접근자가 하나라도 있을 때 또는 커스텀 접근자에서 field 식별자를 참조할 때 생성된다.
// 백킹 필드가 자동으로 생성되지 않는 경우
val isEmpty: Boolean
get() = this.size == 0
Kotlin
복사
백킹 프로퍼티
•
백킹 필드를 직접적으로 사용할 수 없는 경우 백킹 프로퍼티를 통해 해결할 수 있다.
•
private 와 _ 기호를 접두사로 붙인 프로퍼티는 내부적으로만 사용되는 백킹 프로퍼티임을 나타낸다.
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // 타입 매개변수는 추론됩니다.
}
return _table ?: throw AssertionError("다른 스레드에 의해 null로 설정되었습니다.")
}
Kotlin
복사
컴파일 타임 상수
•
컴파일 타임에 값이 알려진 읽기 전용 프로퍼티의 경우 const 수식어를 사용하여 컴파일 타임 상수로 표시할 수 있다.
•
컴파일 타임 상수는 아래 요구 사항을 충족해야 한다.
1.
최상위 레벨(파일 최상위) 프로퍼티 또는 객체 선언(object)이나 동반 객체(companion object)의 멤버여야 한다.
2.
문자열 또는 원시 타입의 값으로 초기화되어야 한다.
3.
custom getter를 가질 수 없다.
•
컴파일러 동작
◦
컴파일러는 상수 사용을 inline하여 상수에 대한 참조를 실제 값으로 대체한다.
◦
필드는 제거되지 않고 리플렉션을 통해 상호 작용할 수 있다.
◦
상수로 선언된 값은 코드에서는 직접 값으로 대체되지만 여전히 리플렉션을 통해 해당 값을 조회할 수 있다.
•
컴파일 타임 상수는 어노테이션에서도 사용할 수 있다.
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED)
fun foo() {
// ...
}
Kotlin
복사
지연 초기화 프로퍼티와 변수
•
non-nullable 타입으로 선언된 프로퍼티는 생성자에서 초기화되어야 하지만 null 체크 없이 클래스 내부에서 프로퍼티를 참조하고 싶다면 lateinit 수식어를 통해 할 수 있다.
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 직접 참조
}
}
Kotlin
복사
•
lateinit 수식어 사용 조건
◦
var 로 선언된 프로퍼티
◦
클래스 본문 내부에서 선언된 프로퍼티 (기본 생성자에서는 사용할 수 없음)
◦
custom getter나 setter가 없는 프로퍼티
◦
최상위 레벨 프로퍼티 및 지역 변수에서도 사용할 수 있음
◦
프로퍼티나 변수의 타입이 non-nullable 이어야 함
◦
원시 타입일 수 없음
•
초기화되지 않은 lateinit 프로퍼티 접근
◦
lateinit 프로퍼티가 이미 초기화되었는지 확인하려면 .isInitialized 를 사용한다.
◦
같은 타입, 외부 타입 중 하나 또는 같은 파일의 최상위 레벨에 선언된 경우 어휘적으로 접근 가능한 프로퍼티에만 사용 가능하다.
if (foo::bar.isInitialized) {
println(foo.bar)
}
Kotlin
복사
위임된 프로퍼티
•
프로퍼티의 동작을 다른 객체에 위임할 수 있게 해주는 Kotlin 기능이다.
•
지연 초기화 값, 맵에서 키로 읽기, 사용자 정의 동작 등 다양한 공통 패턴을 쉽게 구현할 수 있다.
•
by 키워드를 사용하여 위임을 설정하며 getValue와 setValue 메서드를 통해 사용자 정의 위임을 만들 수 있다.