코틀린의 클래스는 주 생성자(Primary constructor)와 한 개 이상의 부 생성자(Secondary constructor)를 가질 수 있다.

주 생성자(Primary Constructor)

클래스 헤더의 일부로, 클래스명과 Optional 파라미터(ex.<T>) 뒤에 constructor키워드와 함께 정의한다.

class Person<T> constructor(firstName: String)

주 생성자에 어노테이션이나 접근 제어자1가 없는 경우에는 constructor 키워드를 생략할 수 있다.

class Person(firstName: String)

주 생성자에는 코드를 쓸 수 없어서, init 키워드가 붙어있는 초기화 블록 내에서 초기화할 수 있다. 이때 초기화 블록은 여러 개를 따로 배치할 수 있으며, 아래와 같은 순서로 실행된다.

class Person(
    name: String,
    out: Unit = println("Primary Constructor") // 1
) {
    val firstProperty = "First property".also(::println) // 2

    init {
        println("First initializer") // 3
    }

    val secondProperty = "Second property".also(::println) // 4

    init {
        println("Second initializer") // 5
    }
}
// 실행 결과
Primary Constructor
First property
First initializer
Second property
Second initializer

주 생성자의 매개 변수는 초기화 블록에서 사용할 수 있다.

class Person(
    name: String,
) {
    init {
        println("$name")
    }
}

클래스 본문에 선언된 속성 초기화에도 사용할 수 있다.

class Person(
    firstName: String,
    secondName: String,
) {
    val fullName = firstName + secondName
}

주 생성자 내에서 프로퍼티 선언과 함께 초기화를 할 수 있다. 이때 후행 쉼표를 쓴다.2
일반 프로퍼티와 마찬가지로 주 생성자에 선언된 프로퍼티는 가변(var)이나 불변(val)이다.

class Person(
    val firstName: String = "",
    var secondName: String = "",
)

생성자에 어노테이션이나 접근 제어자가 있는 경우 constructor키워드를 필수로 붙여줘야 하고, 접근 제어자는 그 앞에 위치한다.

class Customer public @Inject constructor(name: String)

부 생성자(Secondary Constructor)

접두사 constructor를 붙여서 부 생성자를 선언할 수 있다.

class Person(val pets: MutableList<Pet> = mutableListOf())

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this)
    }
}

만약 클래스에 주 생성자가 있으면, 부 생성자는 다른 부 생성자를 통해 간접적으로 주 생성자에게 위임해야 한다. this 키워드를 사용하여 동일한 클래스에 대한 생성자 위임을 할 수 있다.

class Person(val name: String) {
    val children: MutableList<Person> = mutableListOf()

    constructor(
        name: String,
        parent: Person,
    ) : this(name) {
        parent.children.add(this)
    }
}

초기화 블록 내부 코드는 효과적으로 주 생성자의 일부가 된다. 주 생성자에 대한 위임은 부 생성자의 첫 번째 명령문에 접근하는 순간에 발생하므로 모든 초기화 블록 및 속성 초기화 코드는 부 생성자의 본문보다 먼저 실행된다.
클래스에 주 생성자가 없어도 위임은 여전히 암시적으로 발생하며, 초기화 블록도 여전히 실행된다.

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}
// 실행 결과
Init block
Constructor

추상화되지 않은 클래스가 생성자를 선언하지 않으면 인수 없이 생성된 주 생성자를 가질 것이며, 이때 가시성은 public 일 것이다.
클래스가 public 생성자를 가지지 않길 바라면, 가시성이 default가 아닌 비어있는 주 생성자를 선언하면 된다.

class DontCreateMe private constructor() {}

JVM에서 모든 주 생성자 파라미터들이 기본값을 가지고 있는 경우, 컴파일러는 기본값을 사용할 수 있는 파라미터 없는 생성자를 추가적으로 만든다. 이는 파라미터 없는 생성자를 통해 클래스 인스턴스를 생성하는 라이브러리(Jackson, JPA)와 함께 코틀린을 사용하기 쉽게 만든다.

class Customer(val customerName: String = "")

링크

Constructors

주석

  1. Kotlin Docs에서는 'visibility modifier(가시성 수정자)'라는 단어를 사용했지만, 나한테는 '접근 제어자'가 더 익숙한 표현이라서 이렇게 표기했다. 

  2. Kotlin 스타일 가이드에서 권장하는 스타일. Trailing commas