오늘도 더 나은 코드를 작성하였습니까?

kotlin constructor initBlock(코틀린 생성자와 초기화 블록) 본문

Kotlin in Action/코틀린 기초

kotlin constructor initBlock(코틀린 생성자와 초기화 블록)

hik14 2023. 6. 2. 18:38

1.  코틀린 객체 생성 및 초기화의 기본

kotlin class의 생성자를 통해 객체를 생성할때, 자세히 살펴보자.

class Person(val name: String, gender: String = "male") {

    val gender: String

    init {
        this.gender =
            if (gender in arrayOf("male", "female")) gender
            else throw IllegalArgumentException()
    }

    var age = 0

    constructor(name: String, age: Int) : this(name) {
        this.age = age
    }
}

 

1. primary constructor

클래스 이름뒤 ( ... ) 주생성자의 parmeter에 val( 기본 getter 생성)  / var(기본적인 getter/setter 생성)을 앞에 붙혀 property를 생성한다. 하지만, val/var이 붙지 않는다면 단순 parmeter이다.

즉, 위의 예에서 name은 property지만, gender는 단순 parmeter 이다.

 

*  primary constructor는 default 값을 설정할 수 있지만, 구체적인 code를 작성하여 초기화를 하는데 있어 불편합니다.

 

2. init block

 primary constructor를 도와 객체를 초기화합니다.

parmeter로 받은 gender를 이용하여  val gender를 초기화에 있어 구체적인 코드를 작성을 하여 할수 있다.

 

3. subConstructor

primary constructor이외의 방법으로 객체를 생성한다. 

* 클래스에 primary constructor가 있는 경우 각 subConstructor는 직접 또는 다른 보조 생성자를 통해 "반드시" 간접적으로

primary constructor에게 위임해야 합니다. 클래스내에서 다른 생성자에 대한 위임은 this 키워드를 사용하여 수행가능하다.

name, age를 parmeter를 받으며 name은 this(name)을 통해 주생성자를 호출하여 객체 생성을 위임하며, property age의 값을 할당한다.

* 주생성자가 Test() 라면 위임하지 않아도 된다

class Test{
    constructor(str: String){
        println(str)
    }
}

2.  코틀린 객체 생성, 초기화 구체적 순서

많은 경우 kotlin의 주생성를 통해 쉽게 클래스를 작성하고 사용하는것은 코드를 간편하게 작성할 수 있고, 직관적으로 읽기 쉽게 해준다.

하지만, 주생성자 + 초기화 블록 및 부생성자를 모두 사용한다면,  초기화의 진행순서 및 각 블록의 호출순서가 헷갈릴수 있기에 한번 알아보자!

class InitOrderDemo(val primaryConstructorProperty: String = "Primary Constructor Property".also(::println)) {

    val firstProperty = "First property".also(::println)

    val secondProperty = "second property".also(::println)

    init {
        println("First initializer block call")
    }

    constructor(param1: String, param2: Int): this(param1){
        println("First SubConstructor Block call")
    }

    val thirdProperty = "Third property".also(::println)

    constructor(param1: String, param2: Int, param3: Long): this(param1, param2){
        println("Second SubConstructor Block call")
    }

    init {
        println("Second initializer block call")
    }
}

주생성자로 객체 생성시.

부생성자로 객체 생성시.

property와 init block 실제 클래스 선언된(코드가 작성된) 순서대로 default값이 있다면 초기화된다.

또한 먼저 선언된 property만 init block에서 초기화 가능하다.

 

Sub constructor block은 가장 나중에 실행되며, 위임한 순서대로 호출된다.