天天看点

你了解封装类和类的继承以及枚举类之间的恩怨纠葛吗?

作者: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 not found"),
SUCCESS(,"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 关键字所修饰)。而枚举类中的对象都是相同的类型。

说了这么多,我们到底该怎么使用这个封装类,或者说在什么情况下应该使用封装类呢?它应该在那种类似于枚举类,但使用枚举类又不太好实现的场合使用(说了等于没说)。

举个栗子,比如有一个函数,它的其中一个参数是运算的类型,运算方式的种类是有限的,而运算的方式又各不相同。在这样一个场景下,选择封装类是一个更好的选择(尽管普通的类继承也能达到同样的效果)。

最后在用白话文说一遍:如果你所进行的操作,其种类是有限的,并且每一种操作的实现方式各不相同,在这种情况下你应该优先考虑使用封装类。