관리 메뉴

나만을 위한 블로그

[Kotlin] 생성자 정리 본문

개인 공부/Kotlin

[Kotlin] 생성자 정리

참깨빵위에참깨빵 2022. 1. 30. 21:42
728x90
반응형

자바와 100% 호환을 자랑하는 코틀린답게 코틀린 또한 자바처럼 생성자를 갖고 있다.

코틀린에서 생성자는 어떻게 사용할까? 먼저 자바에서 어떻게 사용하는지 확인해보자.

이름과 나이를 받는다고 가정하면 아래와 같이 만들 수 있다.

 

public class ConstructorJavaTest {
    private String name;
    private int age;

    public ConstructorJavaTest(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public ConstructorJavaTest() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

기본 생성자를 사용하거나 생성자 사용 시 두 변수를 매개변수로 넘겨받아 사용하는 방법이 있다.

코틀린에서 위와 같은 일을 하는 생성자는 아래와 같이 만들 수 있다.

 

class ConstructorTest (val name: String, var age: Int) {}

 

자바와 비교해서 변태같이 정말 많이 짧아졌다. 클래스 이름 옆에 소괄호를 쓰고 변수를 선언한 것 뿐인데 생성자 역할을 한다.

코틀린에선 위 형태를 주 생성자라고 부른다. 이 주 생성자의 사용방식은 아래처럼 다양한 방법으로 사용할 수 있다.

 

// 클래스명 옆에 constructor()를 붙이고 init 블록을 사용하는 경우
class ConstructorTest constructor(name: String) {
    val testName: String
    init {
        testName = name
    }
}

// 생성자 매개변수로 값을 받아 클래스 내의 멤버에 대입시켜 사용하는 경우
// 자바에서도 자주 볼 수 있는 방식이다
class ConstructorTest (name: String) {
    val aName = name
}

// 가장 간단하게 생성자를 사용하는 방법
class ConstructorTest (val name: String, var age: Int) {}

 

그러나 코틀린에는 주 생성자만 있을까? 주 생성자가 있다면 부 생성자도 있을 것 같다.

실제로 코틀린에는 constructor 키워드를 사용한 부 생성자 사용방법도 존재한다.

 

class ConstructorTest (var name: String, var age: Int) {
    // name 값만 매개변수로 받는 부 생성자
    // 기본 생성자를 반드시 호출해야 한다
    constructor(aName: String): this(aName, 0)
    // 두 매개변수의 값을 공백, 0으로 설정하는 생성자
    constructor(): this("", 0)
}

 

코드를 보면 ": this(aName, 0)" 부분이 있다. 코틀린에서 콜론(:)을 쓴다는 건 상속을 의미하는데, 여기선 기본 생성자를 상속받았다는 뜻이다.

왜냐면 부 생성자로 만든 생성자들은 반드시 기본 생성자가 갖고 있는 매개변수들을 갖고 있어야 한다.

위 코드에서 주 생성자를 없애보면 this 밑에 빨간 밑줄이 생기며 아래와 같은 에러가 나온다.

 

None of the following functions can be called with the arguments supplied.
제공된 인수로 다음 함수를 호출할 수 없다

 

그리고 자바에서 싱글턴 패턴 사용을 위해 생성자를 private하게 설정했듯 코틀린에서도 private를 붙여 가시성을 지정할 수 있다.

이때 private를 붙이지 않으면 public이 기본 지정된다.

 

class ConstructorTest (var name: String, var age: Int) {
    private constructor(aName: String): this(aName, 0)
    // 접근 지정자를 별도 지정하지 않았으면 기본 public이다
    constructor(): this("", 0)
}

 

그런데 앞서 생성자를 만들 때 사용한 init 블록이란 무엇인가?

 

https://stackoverflow.com/questions/55356837/what-is-the-difference-between-init-block-and-constructor-in-kotlin

 

What is the difference between init block and constructor in kotlin?

I have started learning Kotlin. I would like to know the difference between init block and constructor. What is the difference between this and how we can use this to improve? class Person constru...

stackoverflow.com

init 블록은 기본 생성자 직후에 실행된다. init 블록은 기본 생성자의 일부가 된다. 생성자는 부 생성자다. 기본 생성자에 대한 위임은 보조 생성자의 첫 번째 명령문으로 발생하므로 모든 init 블록의 코드는 부 생성자 본문보다 먼저 실행된다

 

https://kotlinlang.org/docs/classes.html#constructors

 

Classes | Kotlin

 

kotlinlang.org

Constructors

코틀린 클래스에는 기본 생성자와 하나 이상의 보조 생성자가 있을 수 있다. 기본 생성자는 클래스 헤더의 일부고 클래스명과 선택적 타입 매개변수 뒤에 온다. 기본 생성자에 주석이나 가시성 수정자가 없으면 constructor 키워드는 생략될 수 있다.

class Person(firstName: String) { /*...*/ }

기본 생성자는 코드를 포함할 수 없다. 초기화 코드는 init 키워드가 접두사로 붙은 초기화 블록에 배치할 수 있다. 인스턴스를 초기화하는 동안 init 블록은 속성 initializer와 interleaved된 클래스 본문에 나타나는 것과 동일한 순서로 실행된다

 

코틀린 공식문서와 스택오버플로우의 답변을 종합해보면 코틀린 클래스의 기본 생성자 안에 코드를 넣을 수 없으니 init 블록을 사용해 초기화가 필요한 변수를 초기화해 사용하는 것이라고 생각된다.

반응형
Comments