我们一般使用枚举类如下所示
枚举 - enum 示例:
enum class Weekday(val id: Int, val value: String, val display: String){
MON(0, "1", "周一"),
TUE(1, "2", "周二"),
WED(2, "3", "周三"),
THU(3, "4", "周四"),
FRI(4, "5", "周五"),
SAT(5, "6", "周六"),
SUN(6, "7", "周日");
companion object {
private val map = values().associateBy(Weekday::ordinal)
fun fromId(id: Int) = map[id] ?: SUN
fun fromValue(value: String?): Weekday? = when (value) {
MON.value -> MON
TUE.value -> TUE
WED.value -> WED
THU.value -> THU
FRI.value -> FRI
SAT.value -> SAT
SUN.value -> SUN
else -> SUN
}
}
}
枚举类转 密封类 - sealed 示例:
sealed class Weekday(val id: Int, val value: String, val display: String) {
object Mon : Weekday(0, "1", "周一")
object Tue : Weekday(1, "2", "周二")
object Wed : Weekday(2, "3", "周三")
object Thu : Weekday(3, "4", "周四")
object Fri : Weekday(4, "5", "周五")
object Sat : Weekday(5, "6", "周六")
object Sun : Weekday(6, "7", "周日")
companion object {
fun fromId(id: Int) = Weekday::class.sealedSubclasses
.mapNotNull { it.objectInstance }
.firstOrNull { it.id == id } ?: Mon
fun fromValue(value: String) = Weekday::class.sealedSubclasses
.mapNotNull { it.objectInstance }
.firstOrNull { it.value == value } ?: Mon
}
}
在网上看到一篇写的很详细的回答两者之前的区别:sealed class vs enum
enum:每个枚举值不能有自己的唯一属性。被迫为每个枚举值拥有相同的属性:
enum class Week(val display: String?) {
WEEKDAY("Monday"),
WEEKEND(null),
}
sealed:我们可以为每个子类型设置不同的属性:
sealed class Week
class Weekday(val display: String) : Week()
object Weekend : Week()
enum:枚举可以具有抽象函数以及常规函数。但是和属性一样,每个枚举值也必须具有相同的功能:
enum class Week {
WEEKDAY {
override fun isRest() = false
},
WEEKEND {
override fun isRest() = true
};
abstract fun isRest(): Boolean
}
用法:
class WeekManager {
fun isRest(status: Week): Boolean {
return status.isRest()
}
}
sealed:我们可以为不同的子类型使用不同的函数:
sealed class Week
class Weekday : Week(){
fun isWork()= true
}
class Weekend : Week(){
fun isRest()= true
}
这里我们有不同的函数:isWork() 用于Weekday,isRest() 用于Weekend。这使意图更清晰并使代码更具可读性。
用法:
class WeekManager {
fun displayText(day: Week): String = when(day) {
is Weekday -> day.isWork()
is Weekend -> day.isRest()
}
}
如果我们想要所有子类型的通用函数,就和在枚举示例中一样写法就行。
enum:类是隐式 final 的,不能被其他类扩展,只能扩展接口:
interface Workable {}
enum class Week : Workable {}
sealed:不仅本身可以扩展,而且可以扩展其他类以及接口:
sealed class Week : WorkStatus(){}
sealed class Week : Workable{}
class Weekday : Week(){}
enum:都由抽象类 java.lang.Enum 隐式扩展。因此,所有枚举值具有 equals()、toString()、hashCode()、Serializable 和 Comparable 的实现。我们不必定义它们。
sealed:我们需要手动定义它们,或者使用数据类自动实现 equals()、toString() 和 hashcode(),然后手动实现 Serializable 和 Comparable。
enum:
1.枚举不会被垃圾收集,它们会在您的应用程序的整个生命周期中保留在内存中。这可能是有利的,也可能是不利的。
a.优点:垃圾收集过程是昂贵的。对象创建也是如此,我们不想一次又一次地创建相同的对象。因此,使用枚举,您可以节省垃圾收集和对象创建的成本。这是好处。
b.缺点:枚举即使在不使用时也会留在内存中,这会使内存一直被占用。
⚠️ 如果应用程序中有 100 到 200 个枚举,则无需担心所有这些。但是,当您拥有更多数量时,您可以根据事实来决定是否应该使用枚举,例如枚举的数量、它们是否会一直使用以及分配给 JVM 的内存量。
2.在 when 表达式中枚举值的比较会更快,因为在幕后,它使用 tableswitch 来比较对象。
3.在 Android 中,当启用优化时,Proguard 会将没有函数和属性的枚举转换为整数,因此您可以在编译时获得枚举的类型安全性,并在运行时获得整数的性能。
sealed:
1.密封类只是普通类,唯一的例外是它们需要在同一个包和同一个编译单元中进行扩展。所以,他们的表现相当于普通类。
2.密封类的子类型的对象像常规类的对象一样被垃圾收集。因此,您必须承担垃圾收集和对象创建的成本。
⚠️ 当您有低内存限制时,如果您需要数千个对象,您可以考虑使用密封类而不是枚举。因为垃圾收集器可以在对象不使用时释放内存。
4.如果您使用对象声明来扩展密封类,则对象将充当单例并且不会被垃圾收集,就像枚举一样。
5.密封类的类型比较在when表达式中比较慢,因为在后台它使用 instanceof 来比较类型。在这种情况下,枚举和密封类之间的速度差异很小。仅当您在循环中比较数千个常量时才重要。