一、密封類
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 就會出現問題。
而密封類就不會有這個問題,只有文件的編寫者才能創建一個新的子類,從而改變它的取值類型計數。