클래스의 프로퍼티는 다음과 같은 특성을 가지고 있다.
data hiding에 대해 자세히 살펴보자.
코틀린은 프로퍼티가 정의되면 자동으로 디폴트 getter-setter를 생성한다. 이는 인스턴스의 프로퍼티를 . 연산자로 접근할 때, getter-setter를 자동으로 호출하여 사용한다. 자세히 말하자면 직접 메모리에 담겨있는 값에 접근하는 것이 아니라 중간에 getter-setter라는 인터페이스를 두어 데이터를 숨기는 것이다.
class MyClass(val myProperty: String) { ... }
var myProperty: String = initialVaue
get() = field
set(value) {
field = value
}
위와 같이 primary constructor에 프로퍼티를 정의하면 코틀린이 자동으로 아래와 같은 getter-setter를 생성한다. 여기서 field는 프로퍼티의 backing field의 식별자, 즉 실제 메모리에 담겨있는 값을 의미한다. 이렇게 getter-setter를 호출해 값에 접근하거나 변경한다.
class Person(val firstName: String, val lastName: String) {
var fullName:String = ""
get() = "$firstName $lastName“
set(value) {
val name = value.split(" ")
firstName = name[0]
lastName = name[1]
field = value //backing field to hold property value in memory
}
}
위와 같이 프로퍼티를 선언하며 getter-setter를 커스텀하여 사용할 수 있다. 마찬가지로 클래스의 프로퍼티는 초기화해야 되기 때문에 ""로 초기화하고 getter setter를 위와 같이 정의하였다.
그렇다면 primary constructor에 선언된 프로퍼티들의 getter-setter는 어떻게 커스텀 할 수 있을까?
아쉽게도 직접적으로 할 수 없다. 다음과 같은 두가지 방법으로 간접적으로 커스텀이 가능하다.
class Car(speed: Int) {
var speed = speed
get() = field
set(value) {
field = value
}
}
primary constructor에 var/val 키워드를 사용하지 않는 파라미터(지역 변수)를 이용하는 법
fun main(args: Array<String>){
val c = Car(30)
print(c.speed)
}
class Car(@JvmField var speed: Int) {
fun getSpeed() = speed
fun setSpeed(value: Int) { speed = value }
}
JvmField 에노테이션을 이용하여 디폴트 getter-setter 생성을 막고 그대로 필드를 노출시키며, getter-setter를 따로 정의하는 방법
getSpeed 함수와 setSpeed 함수는 원래 코틀린이 자동으로 만들어 주었다.(getter-setter)
@JvmField
Instructs the Kotlin compiler not to generate getters/setters for this property and expose it as a field.