Kotlin 笔记:密封类与代数数据类型

一、密封类

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 就会出现问题。
而密封类就不会有这个问题,只有文件的编写者才能创建一个新的子类,从而改变它的取值类型计数。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章