一.多态的不同方式
对Java而言,多态是面向对象设计的一个重要特征。当我们使用一个子类继承一个父类的时候,这就是子类型多态。另一种是参数多态(泛型)。
1.1子类型多态
class PayCustomerHelper(context: Context) : SQLiteOpenHelper(context, "kotlin.db", null, 1) {
override fun onCreate(db: SQLiteDatabase?) {
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
}
}
上面的方法中通过继承,可以使用父类SQLiteOpenHelper的方法,这就是子类型多态。
1.2参数多态
最常见的参数多态就是泛型。
class ClassA(override val uniqueKey: String) : PayKeyI {
}
class ClassB(override val uniqueKey: String) :PayKeyI {
}
fun persisit(t: T) {
}
参数多态在程序设计语言与类型论中是指 声明与定义函数、复合类型、变量时不指定其具体的类型,而把这部分类型作为参数使用,使得该定义对各种具体类型都适用,所以它建立在运行时的参数基础之上,并且所有这些都是在不影响类型安全的前提下进行的。
1.3对第三方类进行扩展‘
假如当对应的业务类ClassA、ClassB是第三方引入的,而且不可被修改,如果想要给它们扩展一些方法,比如将对象转化为Json。就可以使用Kotlin的扩展语法,给ClassA、ClassB添加方法或属性。
fun ClassA.toJson():String={
... ...
}
如上面代码,给ClassA类扩展了一个将对象转换为Json的toJson方法。需要注意的是,扩展属性和方法的实现运行在ClassA实例,它们的定义操作并不会修改ClassA类本身。这样被扩展的第三方类免于被污染,从而避免了一些因父类修改而可能导致子类出错的问题发生。
1.4特设多态与运算符重载
例子:
下面写法会报错:
fun sum(x: T, y: T): T = x + y
因为某些类型T的实例不一定支持加法操作,而且对于一些自定义类,更希望能够实现各自定制化的“加法语义上的操作”。所以这个例子表现出参数类型多态存在的问题。
换一种思路:
定义一个通用接口,需要支持加法操作的类实现这个接口。
interface Sumable{
fun plusThat(that: T): T
}
data class Len(val v: Int) : Sumable{
override fun plusThat(that: Len): Len = Len(this.v + that.v)
}
通过上面代码发现:当自定义一个支持plusThat方法的数据结构如Len时,这种做法没有问题。但是,如果是针对不可修改的第三方类扩展加法操作时,这种通过子类型多态的技术手段也会遇到问题。
特设多态:一个多态函数有多个不同的实现,依赖于其实参而调用相应版本的函数。
Kotlin支持运算符重载:
data class Area(val value: Double)
operator fun Area.plus(that: Area): Area {
return Area(this.value + that.value)
}
fun main() {
println(Area(1.0) + Area(2.0))
}
Area(value=3.0)
Kotlin中运算符重载:operator关键字,以及Kotlin中内置可重载的运算符plus。operator的作用:将一个函数标记为重载一个操作符或者实现一个约定。plus是Kotlin规定的函数名。除了重载加法,还可以重载减法(minus)、乘法(times)、除法(div)、取余(mod)(Kotlin