這是 Sealed Classes(密封類)系列的第三篇文章,之前的文章從原理寸士、優(yōu)化捡遍、實(shí)戰(zhàn)以不同的角度分別介紹了 Sealed Classes 的強(qiáng)大砸王。
在 Kotlin Sealed 是什么?為什么 Google 都在用 文章中主要包含以下內(nèi)容:
- Sealed Classes 原理分析葱淳?
- 枚舉钝腺、抽象類、Sealed Classes 分別有那些優(yōu)缺點(diǎn)赞厕?
- 分別在什么情況下使用枚舉和 Sealed Classes艳狐?
- 為什么 Sealed Classes 用于表示受限制的類層次結(jié)構(gòu)?
- 在項(xiàng)目中如何使用 Sealed Classes皿桑?
- 禁止在 Sealed Classes 所定義的文件外使用毫目, Kotlin 是如何做到的呢蔬啡?
- ......
在 Kotlin 中的密封類 優(yōu)于 帶標(biāo)簽的類 文章中主要包含以下內(nèi)容:
- 什么是 Tagged Classes(標(biāo)記類)?
- Tagged Classes 的優(yōu)缺點(diǎn)镀虐,以及在項(xiàng)目中所帶來(lái)的影響箱蟆?
- 如何使用 Sealed Classes 優(yōu)化現(xiàn)有的代碼,可以帶來(lái)那些收益刮便?
而這篇文章主要來(lái)介紹 Sealed Classes 在 Kotlin 1.5.0 上帶來(lái)的新特性及原理分析空猜,在開始分析之前,先來(lái)簡(jiǎn)單的回顧一下之前文章的內(nèi)容恨旱。
Sealed Classes
什么是 Sealed Classes辈毯?
Sealed Classes 用于表示受限制的類層次結(jié)構(gòu),其實(shí)這句話可以拆成兩句話來(lái)理解窖杀。
- Sealed Classes 用于表示層級(jí)關(guān)系: 子類可以是任意的類漓摩, 數(shù)據(jù)類、Kotlin 對(duì)象入客、普通的類管毙,甚至也可以是另一個(gè) Sealed
- Sealed Classes 受限制: 必須在同一文件中,或者在 Sealed Classes 內(nèi)部中使用桌硫,在 Kotlin 1.1 之前夭咬,規(guī)則更加嚴(yán)格,子類只能在 Sealed Classes 內(nèi)部中使用
Sealed Classes 的優(yōu)點(diǎn):
- Sealed Classes 使類之間的職責(zé)分明铆隘,提高代碼的可讀性
- 擴(kuò)展性強(qiáng)卓舵,可以在不修改原有的代碼結(jié)構(gòu)的基礎(chǔ)上添加新的參數(shù)或者子類
- 每個(gè)類中不包含無(wú)關(guān)的字段,在一定程度上減少對(duì)象所占用的內(nèi)存
- Sealed Classes 結(jié)合 when 表達(dá)式一起使用會(huì)更加的方便膀钠,when 語(yǔ)句下的所有分支可以通過(guò)快捷鍵
Mac/Win/Linux:Alt + Enter
自動(dòng)生成掏湾,效果如下所示:
這里只是簡(jiǎn)單的回顧了一下之前的內(nèi)容,接下來(lái)我們一起來(lái)看看肿嘲,在新版本 Kotlin 1.5.0 中 Sealed Classes 給我們帶來(lái)了那些優(yōu)化融击。
Sealed Classes 進(jìn)化了
在 2021 年 5 月份,Kotlin 官方發(fā)布了 1.5.0雳窟,在這個(gè)版本中帶來(lái)幾個(gè)非常有用的特性尊浪,而在這篇文章我們主要介紹 Sealed Classes,更多信息請(qǐng)查看 What's new in Kotlin 1.5.0封救。
在 Kotlin 1.0 時(shí)拇涤,子類只能在 Sealed Classes 內(nèi)部中使用,因?yàn)?Sealed class 會(huì)被編譯成 abstract class誉结,并且默認(rèn)的構(gòu)造方法被私有化了鹅士,所以子類必須嵌套在 Sealed Classes 類中。
在 Kotlin 1.1 時(shí)惩坑,允許頂級(jí)的 Sealed Classes 和它頂級(jí)子類在同一個(gè)文件中如绸,因?yàn)榫幾g器會(huì)自動(dòng)生成了一個(gè) 公有 的構(gòu)造方法嘱朽,在子類的構(gòu)造方法中調(diào)用了父類 公有 的構(gòu)造方法,而這些都是 Kotlin 編譯器幫我們做的怔接。
在 Kotlin 1.5.0 中搪泳,放寬了對(duì) Sealed Classes 限制,只需要保證 Sealed Classes 和它的子類扼脐,在同一個(gè)包名和 module 下面即可岸军,這些都是 Kotlin 編譯器幫我們做的。
接下里我們一起來(lái)分析一下為什么 Kotlin 需要升級(jí) Sealed Classes瓦侮?在之前的文章 Kotlin 中的密封類 優(yōu)于 帶標(biāo)簽的類 分析了 Sealed Classes 有很多優(yōu)點(diǎn)艰赞,但是它也有很多不足之處,這也是為什么需要升級(jí) Sealed Classes 的原因:
- Sealed Classes 的子類肚吏,被限制在單個(gè)父類中
- 把所有的代碼放在一個(gè)文件中方妖,會(huì)造成文件臃腫,可讀性下降罚攀,如下所示
sealed class Color {
class Red : Color()
class Blue : Color()
// ...... 更多的顏色
}
sealed class Figure {
abstract fun draw()
}
class Rectangle(val color: Color) : Figure() {
override fun draw() {
}
}
class Round(val color: Color) : Figure() {
override fun draw() {
}
}
class Triangle(val color: Color) : Figure() {
override fun draw() {
}
}
...... // 隨著需求的增加党觅,文件會(huì)越發(fā)龐大
// 通過(guò)快捷鍵 Mac/Win/Linux:Alt + Enter 自動(dòng)生成
fun drawFigure(figure: Figure) {
when (figure) {
is Rectangle -> TODO()
is Round -> TODO()
is Triangle -> when (figure.color) {
is Color.Blue -> TODO()
is Color.Red -> TODO()
}
}
}
在 Kotlin 1.1 中被限制在一個(gè)文件中,隨著需求的增加斋泄,文件只會(huì)越發(fā)的龐大杯瞻,現(xiàn)在放寬了限制之后,我們可以將子類拆分成單獨(dú)的文件炫掐,可以進(jìn)一步的提高代碼的可讀性魁莉。
- 只允許頂級(jí)的 Sealed Classes 和它頂級(jí)的子類在同一個(gè)文件中,對(duì)于非頂級(jí)的 Sealed Classes募胃,所有子類都應(yīng)該在其內(nèi)部聲明旗唁,以下代碼編譯會(huì)失敗
正如你所見 Sealed Classes 還是不夠靈活,非頂級(jí)子類 Yellow 定在 Color 的外面痹束,編譯就會(huì)出錯(cuò)检疫,而在 Koltin 1.5.0 放寬了限制之后,以上代碼可以正常編譯通過(guò)参袱,不僅提高代碼的可讀性,而且靈活性也提高了秽梅。
除此之外還允許在 Sealed Classes 中聲明受保護(hù)的構(gòu)造函數(shù)抹蚀。在 1.5.0 之前所有 Sealed Classes 的默認(rèn)構(gòu)造函數(shù)都是 private,但是在 1.5.0 之后默認(rèn)構(gòu)造函數(shù)都是 protected企垦。
sealed class Figure {
constructor() // 默認(rèn)為 protected
private constructor(area: Double) : this()
}
但是不允許聲明為 public环壤,因?yàn)榫幾g器會(huì)自動(dòng)生成,如果聲明為 public 編譯就會(huì)出錯(cuò):
一起來(lái)看看聲明為 protected 的構(gòu)造函數(shù)钞诡,反編譯后的 Java 代碼都做了什么郑现。Tools → Kotlin → Show Kotlin Bytecode
湃崩。
public abstract class Figure {
private Figure() {
}
private Figure(double area) {
this();
}
// $FF: synthetic method
public Figure(DefaultConstructorMarker $constructor_marker) {
this();
}
// $FF: synthetic method
public Figure(double area, DefaultConstructorMarker $constructor_marker) {
this(area);
}
}
public final class Rectangle extends Figure {
public Rectangle() {
super(1.0D, (DefaultConstructorMarker)null);
}
}
正如你所見,生成的構(gòu)造方法還是私有的接箫,只不過(guò)編譯器會(huì)自動(dòng)生成 公有 的構(gòu)造方法攒读,在子類的構(gòu)造方法中調(diào)用了父類 公有 的構(gòu)造方法。除此變化之外辛友,另外還有一個(gè)重要的特性薄扁,增加了密封接口(Sealed Interface)。
注意:
如果你已經(jīng)升級(jí)到 Kotlin 1.5.0废累,編譯器還提示出錯(cuò)邓梅,請(qǐng)將下面的代碼添加在 build.gradle 中。
compileKotlin {
kotlinOptions {
languageVersion = "1.5"
}
}
Sealed Interface
Sealed Interface 和 Sealed Classes 一樣都是用于表示受限制的類層次結(jié)構(gòu)邑滨,所以它也擁有 Sealed Classes 所有的優(yōu)點(diǎn)日缨,Sealed Classes 擁有的特性 Sealed Interface 也都擁有。
但是不同之處在于 Sealed Classes 被限制在單個(gè)父類中掖看,而 Sealed Interface 支持更靈活的受限制類層次結(jié)構(gòu)匣距,因?yàn)樽宇惪梢詫?shí)現(xiàn)多個(gè) Sealed Interface,如下所示乙各。
// IColor.kt
sealed interface IColor
class Red : IColor
class Blue : IColor
// IArea.kt
sealed interface IArea {
fun area(): Double
}
// IFigure.kt
sealed interface IFigure
class Round() : IFigure, IColor
class Rectangle(val length: Double, val width: Double) : IFigure, IArea, IColor {
override fun area(): Double = length * width
}
Sealed Interface 允許子類有多個(gè)實(shí)現(xiàn)墨礁,自由度更高,使得代碼更加的靈活耳峦,但是它和 Sealed Classes 一樣恩静,被限制在了同一個(gè)包名和 module 下面,如果違反這個(gè)限制編譯就會(huì)出錯(cuò)蹲坷。
關(guān)于 Sealed Interface 相關(guān)的內(nèi)容驶乾,就先介紹到這里,這篇文章主要分析了 Sealed Classes 以及 Sealed Interface 優(yōu)缺點(diǎn)循签,在 Kotlin 1.5.0 中還增加了其他的特性级乐,將會(huì)在后續(xù)的文章中介紹。
全文到這里就結(jié)束了县匠,如果有幫助 點(diǎn)個(gè)贊 就是對(duì)我最大的鼓勵(lì)
代碼不止风科,文章不停
最后推薦我一直在更新維護(hù)的項(xiàng)目和網(wǎng)站:
計(jì)劃建立一個(gè)最全、最新的 AndroidX Jetpack 相關(guān)組件的實(shí)戰(zhàn)項(xiàng)目 以及 相關(guān)組件原理分析文章乞旦,正在逐漸增加 Jetpack 新成員贼穆,倉(cāng)庫(kù)持續(xù)更新,歡迎前去查看:AndroidX-Jetpack-Practice
LeetCode / 劍指 offer / 國(guó)內(nèi)外大廠面試題 / 多線程 題解兰粉,語(yǔ)言 Java 和 kotlin故痊,包含多種解法、解題思路玖姑、時(shí)間復(fù)雜度愕秫、空間復(fù)雜度分析
劍指 offer 及國(guó)內(nèi)外大廠面試題解:在線閱讀
LeetCode 系列題解:在線閱讀
最新 Android 10 源碼分析系列文章慨菱,了解系統(tǒng)源碼,不僅有助于分析問(wèn)題戴甩,在面試過(guò)程中符喝,對(duì)我們也是非常有幫助的,倉(cāng)庫(kù)持續(xù)更新等恐,歡迎前去查看 Android10-Source-Analysis
整理和翻譯一系列精選國(guó)外的技術(shù)文章洲劣,每篇文章都會(huì)有譯者思考部分,對(duì)原文的更加深入的解讀课蔬,倉(cāng)庫(kù)持續(xù)更新囱稽,歡迎前去查看 Technical-Article-Translation
「為互聯(lián)網(wǎng)人而設(shè)計(jì),國(guó)內(nèi)國(guó)外名站導(dǎo)航」涵括新聞二跋、體育战惊、生活、娛樂扎即、設(shè)計(jì)吞获、產(chǎn)品、運(yùn)營(yíng)谚鄙、前端開發(fā)各拷、Android 開發(fā)等等網(wǎng)址,歡迎前去查看 為互聯(lián)網(wǎng)人而設(shè)計(jì)導(dǎo)航網(wǎng)站