Kotlin 문법 - init

느린달팽이·2025년 9월 29일

코틀린 복습

목록 보기
20/25

코틀린에서 init 키워드는 초기화 블록(Initializer Block)을 정의하는 데 사용됩니다. 이는 클래스의 인스턴스가 생성될 때 실행되는 코드를 포함합니다.

기본 개념

  • init 블록은 클래스의 인스턴스를 생성할 때 (생성자가 호출될 때) 실행되는 코드 블록입니다.
  • 주로 클래스 본체 내에서 속성 초기화 로직을 수행하거나 생성 시 필요한 유효성 검사, 계산, 설정 등의 추가적인 작업을 수행하는 데 사용됩니다.
  • *주 생성자(Primary Constructor)**는 클래스 헤더에 정의되며 실행 가능한 코드를 포함할 수 없기 때문에, 이러한 초기화 코드는 init 블록에 위치해야 합니다.
  • 주 생성자(Primary constructor): 클래스 헤더에 정의되는 매개변수
  • init 블록: 객체 생성 시 자동으로 실행되는 초기화 블록
  • 속성(Property): val/var로 클래스 내부에 선언된 멤버 변수
class Student(val name: String, var age: Int) {
    init {
        require(age >= 0) { "나이는 음수가 될 수 없습니다: $age" }
        println("학생 생성 완료 → $name, $age")
    }
}

val s = Student("민수", 20)
// 출력: 학생 생성 완료 → 민수, 20

속성 선언 패턴

1) 가장 간단한 패턴 (헤더에 바로 선언)

class Car(val brand: String = "Hyundai", var color: String = "white")

2) init 블록에서 가공·검증 후 할당

class Car(brand: String, color: String) {
    val brand: String
    var color: String

    init {
        require(brand.isNotBlank()) { "브랜드는 비어 있을 수 없습니다." }
        this.brand = brand.trim()
        this.color = color.lowercase()
    }
}

초기화 실행 순서

  1. 주 생성자 인자 평가
  2. 속성 초기화 → init 블록 실행 (위에서 아래 순서대로)
class Order(id: String) {
    val normalizedId = id.trim()   // 1) 속성 초기화
    init { println("init 실행: $normalizedId") }  // 2) init 블록 실행
}

보조 생성자와 this()

보조 생성자(Secondary constructor)는 반드시 주 생성자에 위임합니다.

그리고 항상 init 블록이 먼저 실행됩니다.

class Person(val name: String, val age: Int) {
    init { println("init 실행: $name, $age") }

    constructor(name: String) : this(name, 0) {
        println("보조 생성자 실행 → $name (age=0)")
    }
}

val p1 = Person("민재")
// 출력: init 실행 → 보조 생성자 실행

상속과 초기화 순서

상위 클래스 → 하위 클래스 순으로 초기화가 진행됩니다.

open class Base(val id: String) {
    init { println("Base init: $id") }
}

class Child(id: String, val tag: String) : Base(id) {
    init { println("Child init: $tag") }
}

val c = Child("ID-1", "TAG-9")
// 출력: Base init → Child init

자주 쓰는 패턴 모음

✅ 데이터 클래스 + 검증

data class Point(val x: Int, val y: Int) {
    init { require(x in 0..100 && y in 0..100) }
}

✅ 기본값 + 이름 있는 인자

class User(val name: String, val age: Int = 0, val country: String = "KR")

val u1 = User("지연")
val u2 = User(name = "Alex", age = 30)

✅ 팩토리 함수 활용 (init 깔끔하게)

class Color private constructor(val r: Int, val g: Int, val b: Int) {
    companion object {
        fun fromHex(hex: String): Color {
            val clean = hex.removePrefix("#")
            require(clean.length == 6)
            return Color(
                clean.substring(0, 2).toInt(16),
                clean.substring(2, 4).toInt(16),
                clean.substring(4, 6).toInt(16)
            )
        }
    }
}

val green = Color.fromHex("#4CAF50")

⚠️ 실수 방지 체크리스트

  • init에 인자를 직접 넣으려 함 → init은 인자를 받지 않습니다.
  • ❌ 생성자에서 val/var 빠뜨림 → 단순 매개변수만 남고 속성이 안 만들어짐.
  • ❌ 모든 검증·가공을 init에 몰아넣음 → 복잡해지면 팩토리 함수 활용 추천.
  • ❌ 자바 연동 시 기본값만 사용 → 필요하면 @JvmOverloads 사용.

📝 결론

  • init 블록은 인자를 직접 받지 않고 주 생성자의 매개변수를 활용하는 구조
  • 초기화 시점에 검증·로그·가공 작업을 넣는 용도로 적합
  • 단순 속성은 생성자 헤더에 바로 val/var 선언하는 게 더 깔끔
profile
한걸음이라도 제대로... 쓰임있는 앱을 만들자

0개의 댓글