안드로이드 코틀린 언어 학습 노트 목차

클래스·객체 — data·sealed·enum·object·생성자

코틀린의 클래스는 자바보다 훨씬 적은 코드로 같은 일을 한다 — 생성자·프로퍼티를 한 줄에 선언하고, data class 하나로 equals·hashCode·toString·copy를 공짜로 얻는다. 또 sealed·object·value class 같은 자바엔 없거나 번거로운 도구로 상태와 싱글톤을 우아하게 모델링한다. 이 장은 코틀린의 클래스 도구 상자를 코드로 훑는다. (출처: Kotlin Docs — Classes / Kotlin in Action 2e Ch 4.)

클래스와 생성자 — 선언과 초기화를 한 줄에

코틀린은 *주 생성자(primary constructor)*를 클래스 헤더에 둔다. val/var를 붙이면 그 자리에서 프로퍼티 선언 + 할당까지 끝난다.

class User(val name: String, var age: Int) {   // 프로퍼티 선언+생성자가 한 줄
    init {                                       // 초기화 블록
        require(age >= 0) { "나이는 음수 불가" }
    }
    constructor(name: String) : this(name, 0)    // 부 생성자 — 주 생성자에 위임
}

val u = User("Kim", 30)   // new 키워드 없음
println(u.name)           // 프로퍼티 직접 접근 (내부적으론 getter)

자바라면 필드 선언 + 생성자 + getter/setter로 수십 줄이 코틀린에선 한 줄이다.

프로퍼티 — 필드가 아니라 접근자

코틀린엔 필드가 아니라 프로퍼티가 있다. u.agegetter/setter 호출이고, 필요하면 커스텀 접근자계산 프로퍼티를 둔다.

class Rect(val w: Int, val h: Int) {
    val area: Int get() = w * h          // 계산 프로퍼티 — 저장 안 하고 매번 계산
    var name: String = ""
        set(value) { field = value.trim() }   // 커스텀 setter, field = 백킹 필드
}

data class — 값 객체를 공짜로

DTO·모델처럼 데이터를 담는 클래스엔 **data class**를 쓴다. 컴파일러가 *equals·hashCode·toString·copy·componentN*을 자동 생성한다.

data class Member(val id: Long, val name: String, val age: Int)

val a = Member(1, "Kim", 30)
val b = a.copy(age = 31)             // 일부만 바꿔 새 객체 (불변 갱신)
println(a == Member(1,"Kim",30))     // true — 내용 비교(equals 자동)
val (id, name) = a                   // 구조 분해 (componentN)
println("$id $name")                 // 1 Kim

copy불변 객체를 다루는 핵심 — 안드로이드의 *단방향 데이터 흐름(UDF)*에서 상태를 일부만 바꿔 새 상태를 만들 때 끝없이 쓴다([andarch] UDF).

enum과 sealed — 제한된 타입으로 상태를 모델링

**enum class**는 고정된 상수 집합이다(메서드·프로퍼티도 가능).

enum class Status(val label: String) {
    LOADING("로딩"), SUCCESS("성공"), ERROR("오류");
    fun isDone() = this != LOADING
}

**sealed class/sealed interface**는 더 강력하다 — *하위 타입이 컴파일 시점에 고정(같은 모듈)*된 제한된 계층이다. 서로 다른 데이터를 가진 상태를 표현하고, when모든 경우를 망라하면 else 없이도 컴파일러가 빠진 분기를 잡는다.

sealed interface UiState {
    data object Loading : UiState
    data class Success(val data: List<Member>) : UiState
    data class Error(val message: String) : UiState
}

fun render(state: UiState) = when (state) {     // else 불필요 — 망라성 보장
    UiState.Loading      -> showSpinner()
    is UiState.Success   -> showList(state.data)   // 스마트 캐스트로 data 접근
    is UiState.Error     -> showError(state.message)
}
다이어그램 로딩 중…

sealed + when 조합이 안드로이드 화면 상태 모델링의 교과서 패턴이다 — enum은 상수만, sealed는 각자 다른 데이터를 담을 때.

object와 companion — 싱글톤과 정적 멤버

코틀린엔 static이 없다. 대신 object(싱글톤)와 companion object(클래스당 하나의 동반 객체)를 쓴다.

object AppConfig {                    // 싱글톤 — 인스턴스 하나, 스레드 안전 지연 초기화
    var baseUrl = "https://api.app.com"
}
AppConfig.baseUrl                     // 클래스명으로 접근

class User private constructor(val name: String) {
    companion object {                // 정적 멤버 자리
        fun create(name: String) = User(name)    // 팩터리 (private 생성자 우회)
    }
}
User.create("Kim")                    // 정적 호출처럼

*익명 객체(object expression)*는 자바의 익명 클래스 대체다 — val listener = object : OnClickListener { ... }.

상속과 인터페이스 — 기본은 final

코틀린 클래스는 기본이 final(상속 불가)이다 — 상속을 의도한 클래스만 open. 이는 "상속을 위한 설계가 아니면 상속을 금지하라"(Effective Java)를 언어 기본값으로 강제한 것이다.

open class Animal(val name: String) {      // open 이라야 상속 가능
    open fun sound() = "..."               // open 이라야 오버라이드 가능
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "멍멍"           // override 키워드 필수
}

interface Clickable {
    fun click()
    fun showOff() = println("clickable")   // 인터페이스 기본 구현
}

value class — 래퍼 비용 0

타입 안전을 위해 원시값을 감싸되 런타임 오버헤드는 없애고 싶을 때 value class(inline class)를 쓴다 — 컴파일 시 내부 값으로 인라인되어 객체 할당이 없다.

@JvmInline
value class UserId(val value: Long)        // Long을 감싸지만 런타임엔 Long 그대로
fun load(id: UserId) { /* ... */ }
// load(42L)  ❌ — 그냥 Long 못 넣음. 타입으로 UserId/OrderId 혼동 방지
load(UserId(42))

정리 — 적은 코드로 정확한 모델

코틀린 클래스의 핵심 — 주 생성자로 선언·초기화를 한 줄에, data class로 값 객체를 공짜로, sealed로 상태를 망라적으로, object/companion으로 싱글톤·정적을, open으로 상속을 의도적으로, value class로 비용 없는 타입 안전을. 이 도구들이 안드로이드의 상태·모델·DI 코드를 간결하고 안전하게 만든다.

한 줄 요약 — 생성자·프로퍼티는 헤더 한 줄. data class=equals/hashCode/copy/구조분해 자동. enum=상수, sealed=각자 데이터 가진 제한 계층(when 망라). object=싱글톤, companion=정적 대체. 클래스는 기본 final(상속은 open). value class=비용 0 래퍼.

(출처: Kotlin Docs — Classes / Data Classes / Sealed / Objects / Kotlin in Action 2e Ch 4 / Effective Kotlin Item 36.)

널 안전 — ?·!!·Elvis·플랫폼 타입·스마트 캐스트함수 심화 — 확장·고차·람다·inline·reified