Android

[Android] 코틀린(Kotlin) 클래스(Class) 생성과 초기화

구루싸 2020. 5. 4. 11:49
반응형
SMALL

오늘의 학습 주제는 코틀린의 클래스(Class)입니다

클래스하면 떠오르는 것은 객체 지향(object-oriented)인데

워낙에 정보가 많은 부분이기 때문에 설명은 생략하고

바로 코드로 진행해보겠습니다

package com.ros.sandbox

import java.io.File
import javax.swing.GroupLayout

class Player(
        /* primary constructor */
        _name: String,
        var healthPoints: Int,
        val isBlessed: Boolean,
        /* information hiding and encapsulation */
        private val isImmortal: Boolean) {

    /* class property */
    var name = _name
        /* getter */
        get() = "${field.capitalize()} of $hometown"
        /* setter */
        set(value) {
            field = value.trim()
        }

    /* computed property */
    val rolledValue
        get() = (1..6).shuffled().first()

    /* late initialization */
    lateinit var alignment: String
    
    /* lazy initialization */
    private val hometown by lazy { selectHometown() }

    /* initializer block */
    init {
        require(healthPoints > 0, { "healthPoints must be more than 0" } )
        require(name.isNotBlank(), { "Player must have own name"})
    }
    /* secondary constructor */
    constructor(name: String) : this(
            /* named argument */
            name,
            healthPoints = 100,
            isBlessed = true,
            isImmortal = true) {
        if ( name.toLowerCase() == "gurusa" ) healthPoints = 40
    }

    /* class function */
    fun castFireball(numFireBall: Int = 2) =
        println("A chunk of fireball appears. (x$numFireBall)")

    fun auraColor(): String {
        val auraVisible = isBlessed && healthPoints > 50 || isImmortal
        val auraColor = if (auraVisible) "GREEN" else "NONE"
        return auraColor
    }

    fun formatHealthStatus() =
        when (healthPoints) {
            100 -> "In best condition"
            in 90..99 -> "There are some abrasions"
            in 75..89 -> if (isBlessed) {
                "There are minor wounds, but they are healing quickly"
            } else {
                "There are minor wounds"
            }
            in 15..74 -> "A lot of hurt"
            else -> "Worst"
        }

    fun initAlignment() {
        alignment = "Good"
    }
    
    fun printAlignment() {
        if ( ::alignment.isInitialized ) println(alignment)
    }
    private fun selectHometown() = File("data/towns.txt")
            .readText()
            .split("\r\n")
            .shuffled()
            .first()
}

위의 코드를 보면 getter, setter, field 부분이 조금 생소합니다

사실 getter와 setter는 자동으로 생성되는데 여기서는 오버라이딩(overriding)하여

getter에서는 대문자 변환과 setter에서는 공백제거를 진행합니다

참고로 var과 val의 차이는 setter의 유무에서 발생합니다

field는 속성에 대해 코틀린이 자동으로 관리해주는 후원 필드(backing field)를 참조합니다

기억할 점은 후원 필드가 산출 속성(computed property)의 경우 생성되지 않는다는 점입니다

이어서 클래스의 속성 초기화 순서를 보면 다음과 같습니다

클래스 속성 초기화 순서

1. 기본 생성자에 정의된 속성에 인자값 지정

2. 클래스 내부에 지정된 속성에 초깃값 지정

3. 초기화 블록(init)에서 속성에 초깃값 지정 및 함수 호출/실행

4. 보조 생성자(constructor)에서 속성의 초깃값 지정 및 기본 생성자 호출/실행

코드 중간에 지연 초기화하는 변수가 보입니다

lateinit 키워드를 이용하는데 해당 속성을 사용하기 전에

초기화해야 된다는 것을 의미합니다

(초기화를 하지 않으면 컴파일 에러가 발생)

만약 초기화 전에 사용된다면 UninitializedPropertyAccessException이 발생됩니다

또 늦 초기화(lazy initialization)을 하는 변수도 있습니다

늦 초기화는 위임(delegation) 메커니즘을 사용해서 구현하고

by 키워드 다음에 대리자(delegate)를 지정합니다

이는 다른 코드에서 최초 사용될 때 lazy 함수의 람다가 실행되어 초기화되고

캐시에 저장되어 람다가 한 번만 실행된다는 장점이 있습니다

아래의 표는 가시 제한자에 대한 설명입니다

아시는 분들은 참고만 하세요~

제한자 설명
public 함수나 속성이 클래스 외부에서 사용될 수 있으며 가시성 제한자가 없을 경우 기본적으로 public이 된다
private 함수나 속성이 정의된 클래스 내부에서만 사용될 수 있다
protected 함수나 속성이 정의된 클래스 내부 또는 이 클래스의 서브 클래스에서만 사용될 수 있다
internal 함수나 속성이 정의된 클래스가 포함된 모듈(module)에서 사용될 수 있다

클래스 속성의 값은 기본적으로 null이 되면 안되지만

null이 될 수 있으면서 변경도 가능할 때가 발생할 수 있습니다

이럴 때는 해당 속성이 null이 되지 않도록 해야합니다

하지만 그렇게 하더라도 스마트 캐스팅(smart casting)할 수 없다는 에러가 발생할 수 있습니다

이것은 경합 상태(race condition)가 생길 가능성이 있다는 것을

컴파일러가 알기 때문인데 이 부분에 대해서는 추후에 학습하도록 하겠습니다

이것으로 오늘의 학습을 마치겠습니다

그럼 이만-_-

반응형
LIST