今天说说Kotlin中的密封类。
在Java中没有密封类
这个概念,所以就没法和Java进行对比了,主要看看Kotlin中的密封类的出现目的和使用方法。
为什么会出现密封类
我们先不说密封类
是什么,先看看为什么需要密封类。下面先通过一段代码来看。
Kotlin代码
interface FatherClass
class SonClass1: FatherClass{
}
class SonClass2: FatherClass{
}
fun check(fatherClass: FatherClass): String =
when(fatherClass){
is SonClass1 -> "1"
is SonClass2 -> "2"
else ->
throw IllegalArgumentException("Unknown Class")
}
fun main(args: Array<String>){
val son1 = SonClass1();
val result = check(son1)
println(result)
}
上面的代码中定义了一个接口,然后两个类实现这个接口。我们在check
方法中通过传入接口对象,使用when
来判断传入的对象是哪种类型。关于when
的使用,可以查看以前的文章有专门介绍。这里使用when
时,必须要添加一个else分支
,否则会报错,无法编译通过。
但是上面的代码存在一个潜在的问题。假如我们这时候再添加一个子类,这时候when
并没有发现我们的子类增加了,也不会报错,可能我们需要给when
增加一个新的分支,但是由于没有报错,可能就会被我们忽略了。
基于上面的原因,Kotlin为了解决上面的潜在问题,便提出了密封类
。
密封类的使用
密封类
需要使用sealed
关键字修饰,并且被sealed
关键字修饰的类,它的子类必须要以嵌套类
的形式在父类中全部声明,关于嵌套类
的想关内容可以查看上一节的文章。下面写一个密封类
的例子。
sealed class SealedClass{
class SonClass1: SealedClass(){
}
class SonClass2: SealedClass(){
}
}
如果你看过前面的内容,你就会有疑问,Kotlin中的类不是默认final
的吗?为什么可以被继承呢?
这是因为被sealed
修饰的类默认是open
的,所以可以被继承,而不需要显式使用open
修饰符。
那我看看密封类的出现,会怎么解决我们上面提出的问题呢?看下面的代码
Kotlin代码
sealed class SealedClass{
class SonClass1: SealedClass(){
}
class SonClass2: SealedClass(){
}
}
fun check(sealedClass: SealedClass): String =
when(sealedClass){
is SealedClass.SonClass1 -> "1"
is SealedClass.SonClass2 -> "2"
}
你会发现when
结构中少了else分支
。对因为在密封类中已经列出了所有的密封类的所有子类,所以就不会有else
的情况。
这样之后,你每次增加一个子类,when
结构就会检查到你增加了子类,就必须要给when
结构添加一个分支,否则就会编译报错,这样就把潜在的问题消灭在了编译阶段。
就像下面这样,增加一个子类必须增加相应的when分支
。
Kotlin代码
package kt
sealed class SealedClass{
class SonClass1: SealedClass(){
}
class SonClass2: SealedClass(){
}
class SonClass3: SealedClass(){
}
}
fun check(sealedClass: SealedClass): String =
when(sealedClass){
is SealedClass.SonClass1 -> "1"
is SealedClass.SonClass2 -> "2"
is SealedClass.SonClass3 -> "3"
}
写在最后
Kotlin中的密封类的出现,在于它定义了一种受限的类继承结构,可以保证我们写出更安全的代码。