Kotlin 열거형 클래스(Enum Classes)


열거형 클래스(enum class)

열겨형 클래스는 class 키워드 앞에 enum를 붙여 선언한다.

각 열거형 상수는 객체이며, 열거형 상수는 쉼표로 구분된다.

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

fun main() {
    println(Direction.NORTH)
}

Output:

NORTH

각각의 Enum은 Enum class의 인스턴스 이므로 특정 값으로 초기화 될 수 있다.

enum class Color(val strRgb: String, val hexaRgb: Int) {
    RED("#f00", 0xFF0000),
    GREEN("#0f0", 0x00FF00),
    BLUE("#00f",0x0000FF ),
}

fun main() {
    println(Color.RED)
    println(Color.RED.name)
    println(Color.RED.strRgb)
    println(Color.RED.hexaRgb.toString(16))
}

Output:

RED
RED
#f00
ff0000

enum 정의 형식

  • enum 키워드를 사용하여 열거체를 정의할 수 있다.
  • 정의된 열거체의 첫 번째 상수값은 0부터 설정되며, 그 다음은 바로 앞의 상수값보다 1만큼 증가되며 설정된다.
  • 불규칙한 값을 상수값으로 설정하고 싶으면 상수의 이름 옆에 괄호(())을 추가하고, 그 안에 원하는 정수로 된 상수값을 명시할 수 있다.
  • 열거체명 오른쪽에 val로 변수를 선언하면 해당 열거형 요소의 상수값을 확인할 수 있다. 자료형 지정을 통해 ordinal 타입을 지정할 수 있다.

enum을 사용하는 이유

  • 인스턴스 생성과 상속을 방지, 상수값의 타입 안정성을 보장한다.
    • 열거형 클래스의 가장 기본적인 사용 이유는 형식이 안전한 열거형(type-safe enums)을 구현하는 것이다.
  • 코드가 단순해지고, 가독성이 높아진다.

익명의 클래스 (Anonymous Classes)

Enum constant는 자신의 anonymous class들과 method들을 선언할 수 있고, base method를 override 할 수 있다.

enum class ProtocolState {
    WAITING {
        override fun signal() = TALKING
    },
    TALKING {
        override fun signal() = WAITING
    };

    abstract fun signal(): ProtocolState
}

fun main() {
    println(ProtocolState.TALKING.signal())
    println(ProtocolState.WAITING.signal())
}

Output:

WAITING
TALKING

Enum class에 멤버를 정의할때는, 멤버 정의와 enum constant 정의를 세미콜론(;)으로 구분해야 한다.
Enum의 항목(entry)들은 중첩된 클래스를 가질 수 없다.

열겨형에서는의 인터페이스 구현 (Implementing Interfaces in Enum Classes)

enum class는 상속 대신 interface 를 사용한다.

interface는 모든 항목을 위한 하나의 인터페이스 멤버를 가지거나 anonymous class 안에 있는 각각의 항목을 위한 인터페이스들을 가진다.

import java.util.function.BinaryOperator
import java.util.function.IntBinaryOperator

enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator {
    PLUS {
        override fun apply(t: Int, u: Int): Int = t + u
    },
    TIMES {
        override fun apply(t: Int, u: Int): Int = t * u
    };

    override fun applyAsInt(t: Int, u: Int) = apply(t, u)
}

fun main() {
    val t = 2
    val u = 3

    println("PLUS($t, $u) = ${IntArithmetics.PLUS.apply(t, u)}");
    println("TIMES($t, $u) = ${IntArithmetics.TIMES.apply(t, u)}");
}

Output:

PLUS(2, 3) = 5
TIMES(2, 3) = 6

열거형 상수 작업 (Working with enum constants)

Enum class는 정의된 enum constant를 리스트를 받아올 수 있고, 열거형 이름으로 enum constant를 받아 올수 있는 Synthetic methods를 가진다.

이런 methods의 Signature 는 아래와 같다.

메소드 설명
EnumClass.valueOf(value: String): EnumClass 인자로 전달된 문자열과 일치하는 해당 열거체의 상수를 반환한다.
EnumClass.values(): Array<EnumClass> 해당 열거체의 모든 상수를 저장한 배열을 생성하여 반환한다.

아래 예제에서는 열거형 클래스의 목록과 특정 열거형 데이터를 받아오고 있다.

fun main() {
    println(Color.valueOf("RED").name)
    println(Color.values().joinToString())
}

Output:

NORTH, SOUTH, WEST, EAST
NORTH

valueOf() 메소드는 일치하는 Enum constant가 없으면 IllegalArgumentException를 발생시킨다.

enumValues<T>(), enumValueOf<T>() 함수를 통해 generic 방식으로 enum class 의 constant에 접근할 수 있다.

enum class RGB { RED, GREEN, BLUE }

inline fun <reified T : Enum<T>> printAllValues() {
    print(enumValues<T>().joinToString { it.name })
}

fun main() {
    printAllValues<RGB>() // prints RED, GREEN, BLUE
}

Output:

RED, GREEN, BLUE

모든 enum constant는 enum 정의내에서의 자신의 이름(.name)과 위치(.ordinal)를 받아 올 수 있는 property를 가진다.

메소드 설명
val name: String 열거형의 이름을 반환한다.
val ordinal: Int 열거형의 인덱스를 반환한다.

아래 예제에서는 이름과 위치를 받아오고 있다.

fun main() {
    println(Color.RED.name)
    println(Color.RED.ordinal)
}

Output:

RED
0

참고