Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

코틀린에서 생성자를 정의하는 여러가지 방법에 대해 정리합니다.
코틀린 생성자는 크게 주 생성자(primary constructor)와 부 생성자(secondary constructor)로 나뉘고 각각 제약이 조금씩 다릅니다.

1. 주 생성자 (Primary constructor)

기본적으로 constructor 키워드를 통해 생성자를 정의할 수 있습니다.
constructor 키워드 앞에 접근 제한자를 지정할 수 있습니다.
constructor 키워드 자체를 생략할 수도 있습니다. 단, 이경우엔 접근 제한자는 지정할 수 없습니다.
이렇게 선언하는 생성자를 주 생성자라고 합니다.

class Person constructor(name: String, age: Int)

// 접근 제한자 지정
class Person private constructor(name: String, age: Int)

// constructor 키워드 생략 가능
class Person(name: String, age: Int)

하지만 이 경우엔 생성자 시그니쳐만 정의할 수 있고 초기화 로직 (내부 프로퍼티에 할당)을 작성할 수 가 없습니다.
즉 위 코드만 가지고는 객체 생성 시 전달되는 name, age를 클래스 내부에서 사용할 수 없는 것입니다.
이러한 상황에 대비해 init이란 키워드가 제공됩니다. 초기화 로직을 포함 추가로 필요한 로직이 있다면 호출할 수 있습니다.
혹은 프로퍼티를 정의하면서 바로 대입해줄 수 있습니다.

class Person(name: String, age: Int) {
    val name: String
    val age: Int

    // 아래 init 블록 통해 초기화 가능
    init {
      this.name = name
      this.age = age
    }

    // 혹은 init 블록 사용 없이 프로퍼티 선언 후 대입
    val name = name
    val age = age
}

하지만 매번 이런식으로 프로퍼티에 값을 할당해주는 것은 상당히 번거로운 일이 될 수 있습니다.
코틀린에서는 생성자 시그니쳐를 작성할 때 인자 선언과 동시에 프로퍼티로 할당해주는 문법을 지원합니다.
아래와 같이 인자 선언할 때 val / var 을 주면 됩니다.
또한

class Person(val name: String, val age: Int)

2. 부 생성자 (Secondary constructor)

주 생성자 이외에 추가로 생성하는 생성자들은 모두 부 생성자가 됩니다.
부 생성자는 주 생성자에 비해 몇가지 제약이 있습니다.

  • 부 생성자주 생성자를 반드시 상속해야합니다.
  • 부 생성자에는 인자 선언과 동시에 프로퍼티 할당을 할 수 없습니다.
class Person(val name: String, val age: Int) {

    constructor(grade: Int) {}  // 오류 발생

    constructor(name: String, age: Int, grade: Int): this(name, age) {  // 이렇게 주 생성자를 상속해줘야함

    }

    constructor(name: String, age: Int, val grade: Int): this(name, age) {  // 부 생성자에서 var / val 사용 불가
    }

}

주 생성자가 없는 클래스가 존재할 수도 있다. 이 경우엔 아래와 같이 부 생성자를 자유롭게 선언해둘 수 있다.

class Person {

    constructor(name: String) { 
    }

    constructor(name: String, age: Int) { 
    }

    constructor(name: String, age: Int, grade: Int) { 
    }

}

다만 이렇게 할 일이 거의 없는게.. 주 / 부 생성자 상관 없이 각 인자에 기본값(default)를 정의해 줄 수 있기 때문에
이를 활용해 대부분 주 생성자 하나로 해당 클래스의 객체 생성 방법을 대부분 다 표현해낼 수 있습니다.

class Person(val name: String, val age: Int, val grade: Int = 1)

fun main(args: Array<String>) {
    val p1 = Person("p1", 20)
    val p2 = Person("p2", 21, 2)
}

안녕하세요 골드입니다.

오늘은 코틀린에 있는 여러 가지 초기화 방법에 대해서 설명을 해보려고 합니다. 어떤 방법이 있는지 그리고 이 방법들 중 어떤 것이 먼저 동작하는지 알아볼 것입니다.

1. 생성자

 - 기본 생성자

클래스의 인스턴스를 생성할 때, 우리는 생성자를 사용합니다. 여러 생성자를 생성하여 인스턴스의 고윳값을 원하는 방식으로 설정할 수 있습니다. 코틀린의 기본 생성자는 이렇게 생겼습니다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

코딩을 하다보면 한 번쯤은 사용한 경험이 있는 익숙한 코드입니다. 함수의 인자를 선언하듯이 Test 클래스의 생성자를 정의할 수 있습니다. 이게 코틀린의 기본 생성자입니다. 정의한 클래스 생성자 매개변수를 그냥 사용할 수도 있고, 클래스 속성의 커스텀 게터와 세터를 정의해야 한다면 일대일 대응 관계로 정의한 후 커스텀하면 됩니다. 생성자 매개변수를 바로 사용할 땐 매개변수 앞에 val 혹은 var 키워드를 붙여야 사용이 가능합니다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

 - 보조 생성자

기본 생성자는 단 하나의 생성자를 정의할 수 있습니다. 그렇기 때문에 여러 생성자를 만들기 위해서는 보조 생성자를 사용하여야 합니다. 보조 생성자는 constructor 키워드를 사용합니다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

this 키워드는 보조 생성자로 생성되는 인스턴스의 기본 생성자를 의미한다. 보조 생성자는 클래스 속성을 초기화하는 대안으로 사용할 수 있다. 하지만 동시에 보조 생성자에서 클래스 속성을 정의할 수는 없다. 

 - 인자

생성자를 정의할 때 인자에 기본값을 부여하거나 이름을 부여할 수 있다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

Test 클래스의 기본 생성자 매개변수 _name에 "student1"이라는 기본값을 설정하였다. 또한, main 함수에서 Test 클래스의 인스턴스를 생성할 때, 기본 인자의 이름을 호출하여 값을 지정하였다. 이름을 호출하여 지정하였기 때문에 생성자에서 정의한 인자의 순서와 다르더라도 정상적으로 작동한다. 예제는 인자가 두 개밖에 없지만, 기본 인자가 많아지거나, Boolean타입의 인자가 많을 경우 지명 인자는 매우 유용한 선택이 될 수 있다.

2. 초기화 블록

두 번째는 코틀린의 초기화 블록입니다. 초기화 블록은 속성 값의 유효성을 검사할 수 있는 하나의 수단으로써 사용할 수 있습니다. 초기화 블록은 init 키워드를 사용합니다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

클래스 생성자 매개변수로 Boolean형 isStudent를 추가하였습니다. 추가한 isStudent는 init 블록 안에서 유효성 검사를 실시합니다. require() 함수 안에 Boolean형 변수 isStudent를 넣었습니다. 만약 isStudent가 true라면 프로그램이 올바르게 작동하겠지만, false라면 IllegalArgumentException이 발생하게 됩니다. Test클래스의 인스턴스를 선언할 때 false로 선언하였기 때문에 예외가 발생한 모습입니다.

3. 초기화 순서

위에 제시된 세 가지 방법과 기본 클래스 속성을 정의하는 방법까지 총 네 가지 방법이 있다. 과연 네 가지 방법들은 어떤 순서를 가지고 초기화되는지 궁금하지 않을 수 없습니다.

Kotlin 생성자 기본값 - Kotlin saengseongja gibongabs

1. 기본 생성자

2. 클래스 내부에 속성

3. 초기화 블록

4. 보조 생성자

순서로 초기화되는 모습입니다.

여기까지 골드였습니다.

감사합니다.

참고자료 : kotlinlang.org/docs/reference/classes.html

빅 너드 랜치의 코틀린 프로그래밍, 제이펍, 조시 스킨, 데이비드 그린핼프 지음, 2019년 발행