你瞭解封裝類和類的繼承以及列舉類之間的恩怨糾葛嗎?
作者:feintkotlin(Kotlin學習網)
Kotlin學習QQ群:543182119
說明:文章的內容是基於Kotlin的語法
對與類的繼承和列舉類,大家應該都比較熟悉。但咱還是要簡單的進行一下說明。
類的繼承就好比是泰迪到處播種,生了一群小泰迪,小泰迪有著他爹的性格,又繼續去播種。生出更小的泰迪。子子孫孫、無窮無盡。
用專業術語來說就是:子類繼承父類,其將會擁有父類所有的可繼承成員,並且可以擁有屬於自己的方法和屬性。對於父類的方法也不用完全生搬硬套,子類可以根據實際需要進行重寫。
上面這段話中出現的 可繼承成員 是指什麼呢?可以繼承的成員比較多,我在就列舉它的對立面,剩下的就是可繼承的成員了。
首先是被 final修飾的成員(包括方法、屬性),在Java中final需要顯示的進行宣告,而在Kotlin中所有的成員預設都是被final修飾的,你要想時某個成員能夠被子類繼承,則需要使用 open 關鍵字進行修飾。
第二個是companion object,類似Java中類內部的靜態成員。前面也提到了,在kotlin中所用的成員預設都是final的,夥伴物件也不例外,而夥伴物件無法使用open關鍵字進行修飾,因此也就無法被繼承
第三個是父類的私有成員無法被子類繼承,這和Java中也是一樣的。
類的繼承就這樣簡單的進行了說明,那麼,列舉類又是一個怎樣的東西呢?你可以把它想象成是一個擁有固定主題的清單。放在裡面得東西結構完全相同,各種屬性就千差萬別了。
在Kotlin中,列舉成員的預設值是他自己的名稱,每個列舉成員還有一個編號,可以通過ordinal屬性獲取到。當然你也可以為成員自定義一些屬性,就像下面這個例子一樣:
enum class RequestCode(val code:Int,val msg:String){
NOT_FOUND(404,"404 not found"),
SUCCESS(200,"success")
}
說了那麼多關於類繼承以及列舉類的內容,(其實也不是蠻多,要真的說起來又是幾千字的功夫。就不再浪費大家的時間了,都還有幾個億的大專案要做呢。)還是想在之後介紹起封裝類的時候,大家能有有一兩個比較的物件。
duang!duang!duang!,這場戲的主角登場了。封裝類,英文名字:sealed classes。這可是個新鮮東西,在Java裡可找不到他的兄弟姐妹呢。你們第一次看到這樣一個名字是什麼感覺?封裝?類本身不就是起封裝的作用嗎?再加一個封裝進行修飾,這究竟是想鬧哪樣!
封裝,在這裡所指的是將一個種群聚合到一起,他們都擁有一個相同的父類。這和繼承十分的相似,子類繼承自父類。寫法上的不同點在於父類需要使用 sealed 關鍵字進行修飾。那麼就僅僅是寫法上的不同嗎?當然不是啦,要不然咱特地寫這麼一篇文章是為了什麼?耍大傢伙嘛。
封裝類和普通的類繼承最大的一點不同在於,封裝類的子類數目是有限的,即可列舉的。而普通的類繼承則是沒有數量限制的或者說是不可列舉的。在這裡咱通過一個Kotlin 中 when 表示式的例子來對普通的類繼承和封裝類進行一下比較。
fun doOpt(opt:Operator)=when(opt){
is Add->{}
is Miners->{}
}
fun watchView(view:View)=when(view){
is OneView->{}
is TwoView->{}
else -> {}
}
sealed class Operator
class Add:Operator()
class Miners:Operator()
open class View
class OneView:View()
class TwoView:View()
由於封裝類是可列舉的,因此在when表示式中當你列舉完所有的可能之後,便不需要使用 else 了,而普通的類繼承是無論如何都要使用的。
在這裡還要一點需要向大家所明白,可能大家也注意到了,封裝類Operator 並沒有使用 open 關鍵字進行修飾,那為什麼,其可以被子類繼承呢?其實 封裝類sealed classes,本質上是一個抽象類,而抽象類預設是可繼承的。
既然封裝類的本質是一個抽象類,那麼你也可以像下面這樣往裡面新增抽象方法:
sealed class Operator{
abstract fun work()
}
封裝類和列舉類也是十分的相似,他們兩都是可列舉的。由於封裝類是通過類繼承的方式進行的實現,因此它所包含的物件可以是不同的型別(都繼承至一個相同的父類,並且這個父類被 sealed 關鍵字所修飾)。而列舉類中的物件都是相同的型別。
說了這麼多,我們到底該怎麼使用這個封裝類,或者說在什麼情況下應該使用封裝類呢?它應該在那種類似於列舉類,但使用列舉類又不太好實現的場合使用(說了等於沒說)。
舉個栗子,比如有一個函式,它的其中一個引數是運算的型別,運算方式的種類是有限的,而運算的方式又各不相同。在這樣一個場景下,選擇封裝類是一個更好的選擇(儘管普通的類繼承也能達到同樣的效果)。
最後在用白話文說一遍:如果你所進行的操作,其種類是有限的,並且每一種操作的實現方式各不相同,在這種情況下你應該優先考慮使用封裝類。