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は、すべての項目のための1つのインターフェースメンバーを持つことも、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:

RED
RED, GREEN, BLUE

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

参考