Edit Page

枚举类(Enum Class)

最终更新: 2024/03/21

枚举类最基本的使用场景, 就是实现类型安全的枚举值:

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

每个枚举常数都是一个对象. 枚举常数之间用逗号分隔.

由于每个枚举值都是枚举类的一个实例, 因此枚举值可以这样初始化:

enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

匿名类

枚举常数可以定义它自己的匿名类, 这些匿名类可以拥有各自的方法, 也可以覆盖基类的方法:

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

    TALKING {
        override fun signal() = WAITING
    };

    abstract fun signal(): ProtocolState
}

如果枚举类中定义了任何成员, 需要用分号将枚举常数的定义与枚举类的成员定义分隔开.

在枚举类中实现接口

枚举类也可以实现接口 (但不能继承其他类), 对于接口的成员函数, 可以为所有的枚举常数提供一个共同的实现, 也可以在不同的枚举常数的匿名类中提供不同的实现. 枚举类实现接口时, 只需要在枚举类的声明中加入希望实现的接口名, 示例如下:

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

//sampleStart
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)
}
//sampleEnd

fun main() {
    val a = 13
    val b = 31
    for (f in IntArithmetics.entries) {
        println("$f($a, $b) = ${f.apply(a, b)}")
    }
}

所有的枚举类都默认实现了 Comparable 接口. 枚举常数值的大小顺序, 等于它在枚举类中的定义顺序. 详情请参见 排序(Ordering).

使用枚举常数

Kotlin 中的枚举类拥有编译器添加的合成的(synthetic)属性和方法, 可以列出枚举类中定义的所有枚举常数值, 可以通过枚举常数值的名称字符串得到对应的枚举常数值. 这些方法的签名如下(这里假设枚举类名称为 EnumClass):

EnumClass.valueOf(value: String): EnumClass
EnumClass.entries: EnumEntries<EnumClass> // 专门的 List<EnumClass>

下面是这些属性和方法的使用示例:

enum class RGB { RED, GREEN, BLUE }

fun main() {
    for (color in RGB.entries) println(color.toString()) // 输出结果为 RED, GREEN, BLUE
    println("The first color is: ${RGB.valueOf("RED")}") // 输出结果为 "The first color is: RED"
}

如果给定的名称不能匹配枚举类中定义的任何一个枚举常数值, valueOf() 方法会抛出 IllegalArgumentException 异常.

在 Kotlin 1.9.0 引入 entries 之前, 是使用 values() 函数来取得枚举常数的数组.

每个枚举常数值也拥有属性: nameordinal, 可以取得它的名称, 以及在枚举类中声明的顺序(从 0 开始):

enum class RGB { RED, GREEN, BLUE }

fun main() {
    //sampleStart
    println(RGB.RED.name)    // 输出结果为 RED
    println(RGB.RED.ordinal) // 输出结果为 0
    //sampleEnd
}

你可以通过 enumValues<T>()enumValueOf<T>() 函数, 以泛型方式取得枚举类中的常数:

enum class RGB { RED, GREEN, BLUE }

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

printAllValues<RGB>() // 输出结果为 RED, GREEN, BLUE

关于内联函数(inline function)和实体化的类型参数(Reified type parameter), 详情请参见 内联函数.

在 Kotlin 1.9.20 中, 引入了 enumEntries<T>() 函数, 作为 enumValues<T>() 函数的未来的替代.

Kotlin 仍然支持 enumValues<T>() 函数, 但我们推荐你改为使用 enumEntries<T>() 函数, 因为它的性能损失较少. 每次调用 enumValues<T>() 都会创建一个新的数组, 而每次调用 enumEntries<T>() 都会返回相同的 List, 这样的性能要高效得多.

例如:

enum class RGB { RED, GREEN, BLUE }

@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Enum<T>> printAllValues() {
    println(enumEntries<T>().joinToString { it.name })
}

printAllValues<RGB>() 
// 输出结果为 RED, GREEN, BLUE

enumEntries<T>() 函数是实验性功能. 要使用它, 需要标注 @OptIn(ExperimentalStdlibApi) 注解来表示使用者同意(Opt-in), 并 将语言版本设置为 1.9 以上.