Kotlin 枚举类(Enum Class)是一种特殊的类,用于表示固定数量的常量集合,例如一周的天数、方向(东、南、西、北)、状态(成功、失败、 pending)等。枚举类在编译时就已确定所有可能的实例,不能动态添加,因此非常适合用于表示一组有限的、明确的选项。
一、枚举类的基本定义
Kotlin 中使用 enum class 关键字定义枚举类,每个枚举常量都是枚举类的实例,之间用逗号分隔,末尾可加逗号或分号(可选)。
示例:简单枚举类
kotlin
// 定义一个表示一周天数的枚举类
enum class DayOfWeek {
MONDAY, // 枚举常量:周一
TUESDAY, // 周二
WEDNESDAY, // 周三
THURSDAY, // 周四
FRIDAY, // 周五
SATURDAY, // 周六
SUNDAY // 周日
}
说明:
- 每个枚举常量(如
MONDAY)都是DayOfWeek类的单例实例,无需手动new创建。 - 枚举类默认继承自
Enum类(Kotlin 自动处理),因此不能再继承其他类,但可以实现接口。
二、枚举类的核心特性与使用
1. 访问枚举常量
直接通过「枚举类名。常量名」访问枚举实例:
kotlin
fun main() {
val today = DayOfWeek.MONDAY
println(today) // 输出:MONDAY(默认调用 toString() 方法)
}
2. 枚举常量的属性与方法
枚举类的每个实例都自带两个核心属性(继承自 Enum 类):
name:枚举常量的名称(字符串形式,如"MONDAY")。ordinal:枚举常量的索引(从 0 开始,如MONDAY的ordinal是 0,TUESDAY是 1)。
此外,枚举类还可自定义属性和方法。
示例:带自定义属性和方法的枚举类
kotlin
// 带参数的枚举类(每个常量可传入自定义属性)
enum class Direction(
val chineseName: String, // 自定义属性:中文名称
val degree: Int // 自定义属性:角度(如东是 0°,北是 90°)
) {
EAST("东", 0),
SOUTH("南", 90),
WEST("西", 180),
NORTH("北", 270); // 末尾分号必须加(后面有方法时)
// 自定义方法:获取反方向
fun opposite(): Direction {
return when (this) {
EAST -> WEST
SOUTH -> NORTH
WEST -> EAST
NORTH -> SOUTH
}
}
// 重写父类方法(可选)
override fun toString(): String {
return "$chineseName($degree°)"
}
}
fun main() {
val dir = Direction.EAST
println(dir.name) // 输出:EAST(枚举常量名)
println(dir.ordinal) // 输出:0(索引)
println(dir.chineseName) // 输出:东(自定义属性)
println(dir.degree) // 输出:0(自定义属性)
println(dir.opposite()) // 输出:西(180°)(调用自定义方法)
println(dir) // 输出:东(0°)(调用重写的 toString())
}
注意:
- 枚举类的构造函数参数需在常量声明时传入(如
EAST("东", 0))。 - 若枚举类有自定义方法,常量列表末尾必须加分号 (
;)分隔。
3. 枚举类的常用方法
除了自定义方法,Enum 类还提供了一些实用的内置方法:
| 方法签名 | 功能说明 | 示例(以 Direction 为例) |
|---|---|---|
values(): Array<T> |
返回所有枚举常量的数组(按声明顺序排列) | Direction.values() → [EAST, SOUTH, WEST, NORTH] |
valueOf(name: String): T |
根据名称获取枚举常量(大小写敏感,不存在则抛异常) | Direction.valueOf("WEST") → WEST |
compareTo(other: T): Int |
比较两个枚举常量的 ordinal 差值 |
EAST.compareTo(WEST) → 0 - 2 = -2 |
name: String / ordinal: Int |
获取名称 / 索引(前面已讲) | - |
示例:内置方法使用
kotlin
fun main() {
// 1. values():获取所有常量
val allDirs = Direction.values()
allDirs.forEach { println(it) } // 输出所有方向
// 2. valueOf():按名称获取常量
val west = Direction.valueOf("WEST")
println(west) // 输出:西(180°)
// 3. compareTo():比较索引
val isEastBeforeSouth = Direction.EAST < Direction.SOUTH // 等价于 0 < 1
println(isEastBeforeSouth) // 输出:true
}
4. 枚举类实现接口
枚举类不能继承其他类(默认继承 Enum),但可以实现一个或多个接口,且每个常量可单独实现接口方法(灵活适配不同行为)。
示例:枚举类实现接口
kotlin
// 定义一个接口
interface Behavior {
fun action(): String
}
// 枚举类实现接口(每个常量可自定义 action() 实现)
enum class Animal : Behavior {
CAT {
override fun action(): String {
return "猫:喵喵叫"
}
},
DOG {
override fun action(): String {
return "狗:汪汪叫"
}
},
BIRD {
override fun action(): String {
return "鸟:叽叽喳喳"
}
}
}
fun main() {
val animal = Animal.DOG
println(animal.action()) // 输出:狗:汪汪叫
}
三、枚举类的高级用法
1. 带抽象方法的枚举类
枚举类可以包含抽象方法,此时每个枚举常量必须重写该抽象方法(类似接口的实现)。
示例:带抽象方法的枚举
kotlin
enum class Operation {
ADD {
override fun calculate(a: Int, b: Int): Int = a + b
},
SUBTRACT {
override fun calculate(a: Int, b: Int): Int = a - b
},
MULTIPLY {
override fun calculate(a: Int, b: Int): Int = a * b
};
// 抽象方法(必须被所有常量重写)
abstract fun calculate(a: Int, b: Int): Int
}
fun main() {
val op = Operation.MULTIPLY
println(op.calculate(3, 4)) // 输出:12
}
2. 枚举常量作为参数
枚举类的实例可作为函数参数,限制输入为固定的常量集合,提高代码安全性。
示例:枚举作为函数参数
kotlin
// 函数参数类型为枚举类 DayOfWeek
fun isWeekend(day: DayOfWeek): Boolean {
return day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY
}
fun main() {
println(isWeekend(DayOfWeek.FRIDAY)) // 输出:false
println(isWeekend(DayOfWeek.SATURDAY))// 输出:true
}
四、枚举类 vs 密封类(Sealed Class)
Kotlin 中还有一个类似的概念「密封类(sealed class)」,两者都用于表示有限的选项,但有以下区别:
| 特性 | 枚举类(Enum Class) | 密封类(Sealed Class) |
|---|---|---|
| 实例数量 | 编译时固定,不能动态添加 | 子类数量固定(必须在同一文件或子文件中定义) |
| 继承关系 | 不能继承其他类,可实现接口 | 可继承其他类,可被其子类继承(子类可为任意类型) |
| 实例类型 | 所有常量都是枚举类本身的实例 | 每个子类都是独立的类型(可包含不同属性和方法) |
| 适用场景 | 表示一组无状态的常量(如状态、类型) | 表示一组有状态的变体(如不同类型的事件、数据) |
示例:密封类(对比枚举)
kotlin
// 密封类(表示不同类型的网络请求结果)
sealed class Result {
data class Success(val data: String) : Result() // 成功(带数据)
data class Error(val code: Int, val msg: String) : Result() // 失败(带错误码和信息)
object Loading : Result() // 加载中(无状态)
}
// 使用密封类(编译器会自动检查所有可能的情况,避免遗漏)
fun handleResult(result: Result) {
when (result) {
is Result.Success -> println("成功:${result.data}")
is Result.Error -> println("失败:${result.code} - ${result.msg}")
Result.Loading -> println("加载中...")
}
}
总结:
- 若需表示「无状态的常量集合」(如方向、状态码),用枚举类。
- 若需表示「有状态的变体集合」(如不同类型的结果、事件),用密封类。
五、枚举类的常见应用场景
- 状态表示 :如
STATUS_SUCCESS、STATUS_FAILED、STATUS_PENDING。 - 类型分类 :如
TYPE_TEXT、TYPE_IMAGE、TYPE_VIDEO(表示消息类型)。 - 配置选项 :如
THEME_LIGHT、THEME_DARK、THEME_SYSTEM(主题配置)。 - 有限集合:如一周天数、月份、方向等。
六、注意事项
- 枚举常量的
name和ordinal是final的,不能修改。 valueOf()方法对名称大小写敏感,若传入不存在的名称,会抛出IllegalArgumentException,建议结合try-catch使用或提前判断。- 枚举类的实例是单例的,多次访问同一个常量会返回同一个对象。
总结
Kotlin 枚举类是表示固定常量集合的强大工具,支持自定义属性、方法、接口实现和抽象方法,用法灵活且类型安全。在需要限制输入为有限选项的场景中,枚举类是替代字符串 / 整数常量的最佳选择,能显著提高代码的可读性和可维护性。