코틀린의 init 블록과 super 호출은 클래스 계층 구조를 고려한 객체의 올바른 초기화를 담당합니다. 이는 자료 구조와 상속에 영향을 미치는 기본 메커니즘입니다.
자바에서는 생성자를 super(...)로 명시적으로 호출하거나 기본값으로 암시적으로 호출할 수 있습니다. 반면에 코틀린에서는 각각의 주 생성자와 보조 생성자 간의 명확한 구분이 있으며, init 블록은 초기화에 사용됩니다.
주요 문제는 속성이 언제 초기화되는지, init 블록이 언제 호출되는지, 특히 클래스 상속 및 주/보조 생성자 결합 시 생성자 호출 순서를 이해하는 것입니다.
코드 예시:
open class Base(val name: String) { init { println("Base init: $name") } } class Derived(name: String, val age: Int): Base(name) { init { println("Derived init: $name, $age") } } fun main() { Derived("Ivan", 25) } // 출력: // Base init: Ivan // Derived init: Ivan, 25
주요 특징:
상속 체계에서 init 블록은 어떤 순서로 실행됩니까?
먼저 슈퍼 클래스의 init 블록이 속성이 초기화된 후 실행되며, 그 다음에 하위 클래스의 init 블록이 자신의 속성을 초기화한 후 실행됩니다.
코드 예시:
open class A { init { println("A") } } class B: A() { init { println("B") } } fun main() { B() } // A -> B
코틀린에서 생성자 외부에서 super()를 호출할 수 있습니까?
아니요, 슈퍼 클래스의 호출은 생성자 선언의 일부로서만 이루어지며 슈퍼 생성자에 인수를 제공해야 합니다.
코틀린에서 보조 생성자가 주 생성자를 호출하지 않을 수 있습니까?
아니요, 모든 보조 생성자는 다른 보조 생성자 또는 주 생성자에게 호출을 위임해야 합니다. 주 생성자는 슈퍼 생성자를 호출하게 됩니다.
개발자가 슈퍼 클래스의 init 블록에서 하위 클래스에 초기화되는 속성을 참조하려고 시도:
open class A { init { println(f()) } open fun f() = "A" } class B : A() { private val s = "B" override fun f() = s }``` **장점:** - 다형성 사용. **단점:** - 슈퍼 클래스의 init 호출 시 속성 s가 아직 초기화되지 않아 결과가 null이거나 오류가 발생합니다. ## 긍정적인 케이스 생성자에서 재정의된 메소드나 속성을 호출하지 않도록 초기화를 분리: ```kotlin open class A { init { println("init A") } open fun f() = "A" } class B : A() { private val s = "B" override fun f() = s init { println(f()) } }``` **장점:** - 초기화되지 않은 데이터에 대한 참조가 없습니다; - 초기화 순서가 보장됩니다. **단점:** - 올바른 초기화를 위해 코드량이 증가합니다.