클래스 생성자
클래스 생성자는 객체를 생성할 때 초기화 블록 다음으로 실행이 된다.
생성자는 주 생성자(Prime Constructor)와 부 생성자(Secondary Constructor) 이 두 가지로 나뉘게 된다.
주 생성자(Prime Constructor)
주 생성자는 클래스 이름 뒤에 constructor 키워드를 사용하여 지정한다.
class User construntor(_nickname: String) {
val nickname: String
init {
nickname = _nickname
}
}
생성자에 private, internal와 같은 가시성 수식어가 없다면 constructor 키워드는 생략이 가능하다.
init 블록이나 프로퍼티 초기화 식에서만 주 생성자의 파라미터 참조가 가능하다.
기반 클래스 생성자 호출
클래스에 기반 클래스가 있다면 주 생성자에서 기반 클래스의 생성자 호출을 해야 한다.
open class User(val nickname: String, val isSubscribed: Boolean = true)
class TistoryUser(nickname: String) : User(nickname)
TistoryUser 클래스가 User 클래스를 상속받고 있다. 그리고 User 클래스의 주 생성자엔 nickname 생성자 프로퍼티가 있다. 따라서 하위 클래스인 TistoryUser에서 기반 클래스인 User를 상속받을 때 생성자를 호출해야 한다.
부 생성자(Secondary Constructor)
부 생성자는 여러 가지 방법으로 인스턴스를 초기화할 방법이 필요할 때 사용한다.
주 생성자가 클래스 이름 뒤에 consturctor 키워드를 사용한다면, 부 생성자는 클래스 몸체에서 constructor 키워드를 통해 정의된다.
open class View {
constructor(ctx: Context) { . . . . }
constructor(ctx: Conxtext, attr: AttributeSet) { . . . . }
}
Class Button: View {
constructor(ctx: Context): this(ctx, MY_STYLE) { . . . . } // 부 생성자 호출
constructor(ctx:Context, attr: AttributeSet): super(ctx, attr) { } // 상위 클래스 생성자 호출
}
주 생성자가 존재하면 부 생성자는 직접 또는 간접적으로 주 생성자를 호출해야 한다.
여기서 간접적으로 호출이 뜻하는 것은 다른 부 생성자를 통해 호출하는 것이다.
open class View(ctx:Context, attr: Attribute, type: Int) {
constructor(ctx: Context): this(ctx, AttributeSet(), 0)
constructor(ctx: Context, attr: AttributeSet): this(ctx, attr, 0)
}
this 키워드를 통해 보조 생성자 호출을 한 후 주 생성자를 호출하는 작업이 필요하다.
주 생성자가 없다면 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에 생성을 위임해야 한다.
인터페이스에 선언된 프로퍼티 구현
코틀린에서는 인터페이스에 추상 프로퍼티를 추가할 수 있다.
interface User {
val nickname: String
}
이는 User 인터페이스를 구현하는 클래스(자식 클래스)에서 name의 값에 접근하기 위한 방법을 제공해야 한다.
이러한 방법에는 다음과 같은 것들이 있다.
interface User {
val nickname: String
}
class PrivateUser(override val nickname: String): User
class SubscribingUser(val email: String): User {
override val nickname: String
get() = email.substringBefore('@')
}
class FacebookUser(val accountId: Int) : User {
override val nickname = getFacebookName(accountId)
}
차례로 보면
PrivateUser 클래스에선 추상 프로퍼티를 구현하는 것이므로 override를 한 후 직접 선언을 한다.
SubscribingUser 클래스에서도 마찬가지로 override를 한 후 custom getter를 통해 프로퍼티를 설정한다.
FacebookUser 클래스에선 초기화 식을 이용하여 nickname값을 초기화한다.
인터페이스에는 추상 프로퍼티뿐만 아니라 getter와 setter가 있는 프로퍼티도 선언할 수 있다.
interface User {
val email: String
val name: String
get() = email.substringBefore("@")
}
User 인터페이스에 추상 프로퍼티인 email과 custom getter인 name 프로퍼티가 함께 있는 형태이다.
둘의 차이점으로는 하위 클래스에서 추상 프로퍼티는 반드시 override를 해야 하지만, custom getter를 사용하면 override를 할 필요가 없다.
getter와 setter에서 지원 필드 접근(Backing Field)
class User(val name: String) {
val address: String = "unspecified"
set(value: String) {
println("changed $field -> $value")
field = value
}
}
접근자 몸체에서 field라는 식별자로 지원 필드 접근을 한다.
getter는 field 값을 읽을 수만 있고, setter에선 값을 읽거나 쓸 수 있다.
접근자 가시성 변경
접근자의 가시성은 기본적으로 프로퍼티의 가시성과 같다.
또는 get이나 set 앞에 가시성 수식어를 추가하여 가시성을 변경 가능하다.
class LengthCounter {
var counter: Int = 0
private set
fun addWord(word: String) {
counter += word.length
}
}
'Programming > Kotlin' 카테고리의 다른 글
코틀린(Kotlin) - 데이터 클래스와 위임 (0) | 2021.10.10 |
---|---|
코틀린(Kotlin) - 클래스 계층(인터페이스, open, final, abstract, 중첩 클래스, sealed 클래스) (2) | 2021.10.03 |
코틀린(Kotlin) - 문자열과 정규식 (0) | 2021.09.25 |
코틀린(Kotlin) - 함수 정의와 호출 (0) | 2021.09.25 |
코틀린(Kotlin) - 예외 처리 (0) | 2021.09.19 |
댓글