枚举是编程中用于表示一组固定常量的强大工具。在Kotlin中,枚举类(enum class)提供了比Java枚举更丰富的功能,包括属性、方法和接口实现等。本文将详细解析Kotlin枚举类的定义方式、核心方法、常量初始化以及高级用法。
一、枚举类的定义与核心方法
枚举类使用 enum class 关键字声明。它本身是一个类,但不能直接创建实例。类体中定义的每个枚举常量都是该类的一个单例实例。
Kotlin为枚举类自动提供了一些有用的属性和方法:
| 属性/方法 |
功能描述 |
.ordinal |
获取枚举常量在定义中的索引位置(从0开始)。若索引越界会抛出 ArrayIndexOutOfBoundsException。 |
.compareTo() |
比较两个枚举常量的索引。A.compareTo(B),若A索引小于B则返回-1,相等返回0,大于则返回1。 |
.name 或 toString() |
获取枚举常量的字面名称。 |
values() |
获取包含所有枚举常量的数组。 |
valueOf(name: String) |
根据名称字符串获取对应的枚举常量。若名称不存在,则抛出 IllegalArgumentException。 |
enumValues<T>() / enumValueOf<T>() |
功能同上,从Kotlin 1.1版本起支持,提供了泛型访问方式。 |
.declaringClass |
通过枚举常量获取其所属的枚举类(Kotlin中为属性,对应Java的getDeclaringClass()方法)。 |
下面的代码展示了枚举类的基本定义和常用方法的调用:
enum class Demo {
// 枚举常量,规范使用大写。若要定义类方法,需用分号(;)结尾
RED, BLUE, YELLOW, GREEN;
fun printName() {
// 使用when表达式进行判断是处理枚举的常用方式
when(this) {
RED -> println("RED")
BLUE -> println("BLUE")
YELLOW -> println("YELLOW")
GREEN -> println("GREEN")
}
}
}
// 调用示例
println(Demo.BLUE.ordinal) // 输出:1
println(Demo.BLUE.name) // 输出:BLUE
val aa = Demo.valueOf("GREEN") // 返回GREEN常量
val bb = enumValueOf<Demo>("GREEN") // 泛型访问方式
val cc = Demo.values()[2] // 获取索引为2的常量,即YELLOW
Demo.values().forEach { print("$it,") } // 输出:RED,BLUE,YELLOW,GREEN,
enumValues<Demo>().forEach { print("$it,") } // 泛型访问方式
Kotlin中的 when 表达式是处理多分支逻辑和控制流的利器,与枚举类搭配使用能让代码更加清晰。
二、枚举常量的初始化
每个枚举常量都是其枚举类的实例,因此可以为枚举类定义主构造函数,并在声明常量时进行初始化。
注意:如果在枚举常量声明后还需要定义额外的属性或函数,必须用分号 ; 将常量列表与类成员分隔开。
// 枚举类带主构造函数
enum class Demo(var str: String, var age: Int) {
RED("张三", 18),
BLUE("李四", 22),
YELLOW("王五", 15); // 此处分号不可少,用于分隔常量与成员
// 枚举类自定义的属性和函数
var gender: Boolean = false
fun show() = println(str + age)
}
// 调用示例
println(Demo.BLUE.str) // 输出:李四
println(Demo.BLUE.age) // 输出:22
Demo.RED.show() // 输出:张三18
println(Demo.RED.gender) // 输出:false
三、枚举常量的匿名类
枚举常量可以重写其枚举类中开放的(open)或抽象的(abstract)成员,表现为一个匿名类。这为每个常量提供了独特的行为。
enum class Demo {
RED {
// 为RED常量重写抽象属性和函数
override var str = "RED,str"
override fun show() { println("RED,show") }
override fun method() { println("RED,method") }
};
// 枚举类中定义需要被重写的成员
abstract fun show()
open fun method() { println("Demo,method") }
open var str: String = "Demo,str"
}
四、实现接口
枚举类不能继承其他类,但可以实现一个或多个接口。既可以在枚举类中统一实现接口方法,也可以由各个枚举常量在其匿名类中分别实现。
interface AA { fun showAA() }
interface BB { fun showBB() }
enum class Demo : AA, BB {
RED {
// RED常量覆盖了统一实现的showAA,并自行实现了showBB
override fun showAA() { println("RED,showAA") }
override fun showBB() { println("RED,showBB") }
},
BLUE {
// BLUE常量使用了类统一的showAA,但自行实现了showBB
override fun showBB() { println("BLUE,showBB") }
};
// 在枚举类中为所有常量统一实现接口AA的方法
override fun showAA() { println("DEMO,showAA") }
}
// 调用示例
Demo.RED.showAA() // 输出:RED,showAA (常量自身覆盖)
Demo.RED.showBB() // 输出:RED,showBB
Demo.BLUE.showAA() // 输出:DEMO,showAA (使用类统一实现)
Demo.BLUE.showBB() // 输出:BLUE,showBB
这种灵活的实现方式使得枚举类非常适合用来实现状态机等设计模式。在Android开发中,枚举常用于定义页面状态、网络请求结果等固定的类型,结合sealed class(密封类)可以构建出更严谨的状态管理系统。