노트/Java to Kotlin

클래스와 프로퍼티

작성

step 09(클래스)에서 적은 것이다.

클래스 한 줄

class KotlinPerson(val name: String, var age: Int)

풀어 쓰면 이렇다.

class KotlinPerson constructor(name: String, age: Int) {
    val name = name
    val age = age
}
  • constructor 키워드는 생략할 수 있다.
  • 생성자 파라미터에 val 이나 var 를 붙이면 그 자리에서 프로퍼티가 만들어진다.
  • val 프로퍼티는 getter 만, var 프로퍼티는 getter 와 setter 가 자동으로 생긴다.
  • body 가 없으면 {} 를 생략할 수 있다.
  • Java 클래스의 getter 와 setter 도 Kotlin 에서는 .필드 로 부른다.
val junha = KotlinPerson("junha", 20)
junha.age = 30
println("junha = ${junha.name} ${junha.age}")

val leo = JavaPerson("leo", 20)
println("leo = ${leo.name}")   // Java 의 getName() 을 .name 으로 쓴다

init, custom getter 와 setter, 부생성자

class KotlinPersonV2(name: String, var age: Int) {
    // 초기화 시점에 한 번 호출된다
    init {
        if (age <= 0) {
            throw IllegalArgumentException("나이는 ${age} 일 수 없습니다.")
        }
        println("init 블록 실행")
    }

    var name = name
        set(value) {
            field = value.uppercase()
        }
        get() = field.uppercase()

    // 주생성자 외에 부생성자(secondary constructor)를 더 만들 수 있다
    constructor(name: String) : this(name, 1) {
        println("secondary constructor 1")
    }

    constructor() : this("이름 없음") {
        println("secondary constructor 2")
    }

    fun isAdult(): Boolean {
        return this.age >= 20
    }

    // 함수 대신 프로퍼티처럼 보이게 하는 custom getter
    val isAdultV2: Boolean
        get() {
            return this.age >= 20
        }

    val isAdultV3: Boolean
        get() = this.age >= 20
}
  • init 블록은 객체를 만들 때 한 번 실행된다. 값 검증을 여기서 한다.
  • custom getter 나 setter 안에서 name 이라고 쓰면 바로 옆의 getter 를 다시 불러 무한 루프가 된다. 자기 자신을 가리키는 field(backing field)를 써야 한다.
  • 다만 이 방법도 굳이 쓰지 않는다. 필드를 바꿀 때는 업데이트 함수를 쓰기 때문에 setter 자체를 지양하고, 대문자로 바꿔 보여 주려면 그 요구사항을 담은 getter 를 따로 만드는 편이 낫다.
  • 부생성자는 this(...) 로 주생성자나 다른 부생성자를 불러야 하고, 체이닝되면 println 이 역순으로 실행된다.
  • 부생성자보다 default parameter 를 권장한다. 객체를 다른 객체로 변환할 때는 부생성자를 쓸 수 있지만 정적 팩토리 메서드가 더 낫다. Kotlin 정도 쓰면 부생성자를 쓸 일이 거의 없을 것 같다.
val cream = KotlinPersonV2()
// init 블록 실행
// secondary constructor 1
// secondary constructor 2
println(cream.isAdultV3)

요약

  1. 필드를 만들면 getter 와 setter 를 자동으로 만들어 준다. 이 필드와 getter, setter 를 합쳐 프로퍼티라고 부른다.
  2. 주생성자가 필수다.
  3. constructor 키워드로 부생성자를 더 만들 수 있지만 default parameter 를 추천한다.
  4. 실제 메모리에 있는 것과 무관하게, 함수로 만들 수 있는 것을 프로퍼티인 것처럼 custom getter 로 둘 수 있다.
  5. custom getter 와 setter 에서 무한 루프를 막으려면 backing field 를 쓴다.