一、密封类
Kotlin 类开放性排序
- 普通类(不加修饰符,不能继承,默认是
final
的) - 密封类(
sealed
修饰符,有条件继承) - 开放类(
open
修饰符,无条件继承)
密封类的限制
-
可以继承,但只能在当前文件继承
- 在本类内继承
- 在类外被同级类继承(不能在一个同级类的内部被继承)
sealed class A { class B: A() // OK, B is not sealed class } class C: A() // OK, B is not sealed class class D { class E:A() // not OK }
-
不能实例化,因为它的构造方法是私有的(它还是一个抽象类)
-
它的子类如不声明 sealed,则不是一个密封类
密封类的作用
一个更强大的枚举。
枚举类:对象数量固定。
密封类:子类数量固定。
它们都可以实现:
在用于 when 表达式判断时,可以不用写 else(在 when 没有覆盖到所有情况时报错,只在 when 表达式用于返回一个值时生效)。
密封类强于枚举类的地方:
枚举类固定数量的是对象。所有的枚举对象都是一个类,不好区分不同的行为。
密封类固定数量的是子类。子类可以有自己的属性、方法,更加灵活。
如:
sealed class Shape {
class Circle(val radius: Double) : Shape()
class Rectangle(val width: Double, val height: Double) : Shape()
class Triangle(val base: Double, val height: Double) : Shape()
}
fun getArea(shape: Shape): Double = when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
is Shape.Triangle -> shape.base * shape.height / 2.0
}
二、代数数据类型
代数数据类型
ADT(Algebraic Data Type),一种组合数据类型,即由其他数据类型组合成的类型。两种常见的代数数据类型是积类型
、和类型
。
计数
一个类型取值的种类数。
如:
Boolean 是 2
Unit 是 1
String 是无限
Int 是无限
积类型
如 Boolean、Unit 的积类型是 BooleanUnit,它的计数是 2*1=2。
和类型
枚举可以看作一种和类型,它的计数是枚举子项(对象)的个数。
密封类也可以看作一种和类型,它的计数是子类的个数。
代数数据类型的好处
类型安全,即计数固定,所以 when 可以省略 else。
为什么要用密封类,而不是 open 类?
一个 open 类可以被继承,那么它的取值类型计数是可以变化的,比如第三方库中的一个文件中声明了一个类,写了一个没有 else 的 when。然后宿主中有个类继承了它,那这个 when 就会出现问题。
而密封类就不会有这个问题,只有文件的编写者才能创建一个新的子类,从而改变它的取值类型计数。