Post

(Kotlin) Class, 생성자

extends / implements구분 없이 그냥 kt :붙이고 적는데, 클래스 상속인 경우 super class의 생성자를 호출해야 하므로 ()를 붙여주어야 하고 인터페이스 구현인 경우 생성자가 없기 때문에 붙이지 않아야 하므로 이를 보면 둘을 구분할 수 있다.

주 생성자(primary constructor)

주 생성자는 클래스 이름 뒤에 오는 ()로 둘러싸인 코드를 의미한다. 주 생성자의 파라미터는 1. 초기화 블록, 2. 프로퍼티 초기화 식, 3. 주 생성자 자체 에서만 접근할 수 있다.

1. 정석대로 초기화하면 이런 식이다.

생성자를 정의할 때는 contsructor 키워드를 사용한다. 주 생성자의 body(초기화 블록) 지정은 init 키워드를 사용한다.

1
2
3
4
5
6
7
class User1 constructor(_name: String) {
    val name: String
    init {
        name = _name
        // this.name = _name    java나 python처럼 이렇게 해도 된다.
    }
}
2. 굳이 init을 사용할 필요가 없는 경우.

Note ) 주 생성자 앞에 별다른 애노테이션이나 가시성 변경자가 없다면 constructor를 생략할 수 있다.

1
2
3
class User2(\_name: String) {
val name = \_name
}
3. 주 생성자에서 파라미터를 받으면서 동시에 프로퍼티 생성 및 초기화.
1
class User3(val name: String)

부 생성자(secondary constructor)

코틀린은 디폴트 파라미터를 지원하기 때문에 보통 주 생성자 만으로 해결이 되는데, 파라미터 목록에 따라 다른 생성 방법을 지정해야 하는 경우 여러 개의 생성자를 정의해야 하는 상황도 있다.

  1. 디폴트 파라미터. 안되면
  2. 정적 팩터리 메소드 패턴 . 이것도 안되면
  3. 부 생성자를 고려한다.

Effective Kotlin Item 33 , Effective Java에서 얘기하듯 추가적인 생성자(부생성자) 보다는 정적 팩터리 메서드를 사용하는 것이 낫다.

주 생성자와 부 생성자를 함께 사용하는 경우

Note ) 주 생성자가 존재한다면 반드시 호출되어야 하므로, 부 생성자에서 호출해주어야 한다. Note ) 부 생성자의 arg에는 val을 적을 수 없다.

1
2
3
4
5
6
class User (val name: String){
    var nick = ""
    constructor(_name: String, _nick: String) : this(_name){  // 주 생성자 호출
        nick = _nick
    }
}
주 생성자를 사용하지 않고 부 생성자만 사용하는 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
open class View {
//    constructor(ctx: Context) {
//    }
    constructor(ctx: Context, attr: AttributeSet) {
    }
}
class Button : View {
    constructor(ctx: Context)
        : this(ctx, MY_STYLE) {    // 자신의 다른 생성자에 객체 생성을 위임
    }
    constructor(ctx: Context, attr: AttributeSet)
        : super(ctx, attr) {       // View 생성자에 객체 생성을 위임
    }
}

Note) 클래스에 주 생성자가 없다면 모든 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에게 생성을 위임해야 한다.

인터페이스의 추상 프로퍼티

인터페이스에 프로퍼티를 선언할 수 있는데, 인터페이스가 상태를 가질 수는 없기 때문에 프로퍼티를 뒷받침하는 필드는 없다. 다만 그때그때 값을 계산해서 돌려줄 수 있는 게터와 세터를 지정할 수는 있다.(확장 프로퍼티와 유사 하다.)

1
2
3
4
5
interface User {
    val email: String    // 반드시 override 해야 한다.
    val nick: String     // override하지 않고 사용할 수 있다.
        get() = email.substringBefore('@')
}
This post is licensed under CC BY 4.0 by the author.