kotlin密封sealed class/interface的迭代之旅
highlight: vs theme: devui-blue
大家好,kotlin密封類sealed class
不知道大家日常開發中有沒有用到,這個在封裝網絡狀態、UI狀態等方面都是非常有幫助的;此外kotlin1.5版本還提供了密封接口sealed interface
進一步拓展了密封的使用場景;而且為了方便大家使用,kotlin高版本密封類的受限制層次結構也發生了變化。
如果上面的特性你都不是很瞭解,沒有關係,那就趕緊往下仔細閲讀文章瞭解一下吧。
一. 密封類sealed class
密封類大家可以理解為一個抽象類(其實它本質上就是一個抽象類),定義一些通用的行為或者標識,然後子類繼承該密封類,大家看下下面這個例子:
```
sealed class NetworkState
data class Success<T>(val response: T) : NetworkState<T>()
data class Fail(val error: Throwable?) : NetworkState<Nothing>()
object NetDown : NetworkState<Nothing>()
} ```
PS:題外話:為什麼NetworkState
類泛型需要增加out
聲明?
這裏我們看下
Fail
類,可以看到它繼承的父類為NetworkState<Nothing>
,在kotlin中,Nothing
是任意類的子類。這裏的場景簡單表述為就是Nothing
可以是A類的子類型,但是卻不代表NetworkState<Nothing>
是NetworkState<A>
的子類型。想要實現這個效果,那就得要讓
NetworkState
泛型支持協變,在java中使用extends
,在kotlin中就得使用out
聲明。
這裏我們定義一個密封類NetworkState
封裝網絡狀態,以及使用子類Success、Fail、NetDown
分別標識請求成功、失敗和斷網的具體狀態。
由於每次網絡請求成功的響應數據、失敗異常都有可能不同的,所以這裏我們支持Success
和Fail
動態創建,而斷網狀態是不會發生變化,所以使用了單例創建NetDown
。
在代碼中我們就可以這樣使用:
fun <T> response(state: NetworkState<T>) {
when (state) {
is NetworkState.Success -> {
//響應成功
val data = state.response
}
is NetworkState.Fail -> {
//響應失敗
val error = state.error
}
is NetworkState.NetDown -> {
//斷網處理
}
}
}
使用起來就如上面所説的,看起來抽象類也能實現這種效果,那為啥kotlin官方要專門搞一個密封類sealed class出來呢,這裏説下本人的看法:
- 定製優化
對密封類進行的when
遍歷處理,kotlin1.5.30版本新增了一個特性:
when表達式會對是否羅列出密封類的所有子類並進行處理進行校驗,一旦發現漏處理了其中的一個或者多個,會進行告警,高版本1.7及以上會直接給你報錯,這對於保證代碼安全行方面還是非常的友好的。
如果想要啟動這個特性,需要在build中新增如下配置:
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.6"
}
}
}
如果kotlin1.7版本以下想要將告警轉化為error報錯,直接在上面的配置中增加配置progressiveMode = true
即可。
- 方便管理
這個放在下面的密封受限制層次結構的變化中進行講解。
上面的這種密封類有一個不好的地方就是單繼承的問題,本質上密封類的本質就是個抽象類(下面會原理分析),所以子類最多隻能繼承一個類,而下面的密封接口密封接口sealed interface
就解決了這個問題:支持子類實現多個密封接口。
二. 密封接口sealed interface
密封接口的工作效果和密封類相同,最終的區別就是我們上面提及的一個類可以實現多個密封接口, 接下來我們實際操作下 :
``` sealed interface Language { val language: String }
sealed interface Location { val location: String }
sealed interface Family { val family: String }
data class Woman( override val language: String, override val location: String, override val family: String ) : Language, Location, Family
data class Child( override val language: String, override val location: String, override val family: String ) : Language, Location, Family ```
使用起來也和上面一樣:
三. 密封受限制繼承層次結構的變化
在kotlin1.5以下,定義的密封類的子類一定要和密封類在同一個文件中,否則就會報錯,比如:
kotlin1.4.30版本中,在kotlin1.5這個文件中新增新增一個密封類
在另一個文件中定義子類繼承該密封類就會報錯:
而到了kotlin1.5.0版本,由於新增了這麼一個特性:
將子類繼承密封類的限制放大到了整個package下,所以同一個包下的其他文件中,定義子類繼承密封類將不會產生報錯。
請注意,密封類的子類不能是匿名類和局部類:
四. 密封原理探析
這裏我們簡單瞭解下密封類的實現原理,反編譯看下:
如前面所説,密封類本質上就是個抽象類,下面的子類都是繼承該抽象類:
五. 總結
本篇文章主要是講解了密封類和密封接口的使用及原理,同時對於密封子類的受限制繼承層次結構的變化做了一個説明,還擴展了一個小技巧:如何開啟when遍歷密封類是否羅列所有子類的處理場景並作告警處理的特性以及如何將告警轉化為error報錯。
希望本篇文章能對你所有幫助,可以點贊收藏支持下。
六. 歷史文章
@JvmDefaultWithCompatibility優化小技巧,瞭解一下~
優化@BuilderInference註解,Kotlin高版本下了這些“毒手”!
七. 參考鏈接
https://kotlinlang.org/docs/whatsnew15.html
本文正在參加「金石計劃」
- kotlin密封sealed class/interface的迭代之旅
- 2022年12月12日—2022年12月25日Android精品文章一覽
- Sqlite簡易性能優化方案,給你的應用插上“翅膀”
- 築基篇:設置界面的開發利器Preference Library,瞭解一下~
- Android消息機制完整的執行流程,瞭解一下
- 你可能需要了解下的Android開發技巧(二)
- 超有用的Android開發技巧:攔截界面View創建
- Handler創建的幾個必備知識點,瞭解一下
- Android消息機制中Message常用的幾種監控方式
- 數見不鮮的RecyclerView使用技巧,你瞭解嗎(一)?
- 常用到的幾個Kotlin開發技巧,減少對業務層代碼的入侵
- 超好用的官方core-ktx庫,瞭解一下(終)~
- Take a look,從delay()方法看協程的掛起與恢復
- 超好用的官方core-ktx庫,瞭解一下~
- 官方core-ktx庫能對SparseArray系列、Pair開發帶來哪些便利?
- 官方core-ktx庫能對富文本Span開發帶來哪些便利2
- 你需要了解的官方core-ktx庫能對開發帶來哪些便利1
- LeakCanary如何監聽Fragment、Fragment View、ViewModel銷燬時機?
- 非反射動態設置TabLayout指示器的寬度
- 探究EventBus粘性事件實現機制