1. 多态
当我们用一个子类继承一个父类的时候。这就是子类型多态。另一个多肽是参数化类型,也就是泛型。此外,C++的运算符重载叫特色多态。
用子类型替换超类型实例的行为就是我们通常说的子类型多态。
1.1 对第三方类进行扩展
假使当对应的业务类A和B是第三方引入的,且不可被修改时。如果我们想要给他扩展一些方法。比如将对象转化为json。利用之前介绍的多态技术就显得比较麻烦。
fun ClassA.toJson():String{
}
kotlin支持扩展的语法。利用扩展,我们就能给当前类添加方法和属性,从而换一种思路来解决上面的问题
。扩展属性和方法的实现运行在A实例上。他们的定义操作并不会修改类的本身
。这样就为我们带来了一个很大的好处,及被扩展的第三方类免于被污染。从而避免一些因负累修改而可能导致此类出错的问题发生
2 特设多态和运算符重载
基本数据一般可以直接运算,但是对象之间就没法直接参与运算。
data class Area(val value:Area)
opertor fun Area.plus(that:Area):Area{
return Area(this.value+thar.value)
}
我们可以采用扩展的语法来解决问题。此外,kotlin原生支持了一种语言特性来很好地解决问题,这就是运算符重载
Operator它的作用是将一个函数标记为重载一个操作符或者实现一个约定
。除了重载加法,我们还可以通过重载减法、乘法、除法、取余等函数来实现重载运算符。
a in b // b.contains(a)
3. 扩展函数
3.1 开放封闭原则
对开发者而言,业务需求总是在不断变动。在修改现有代码的时候,我们应该遵循开放封闭原则及软件,实际应该是可扩展。而不可修改的。也就是说,对扩展开放,对修改封闭
开放、封闭原则是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是这一目标的直接体现
但是在我们实际开发当中,为了实现某个需求,引入了一个第三方库。但某一天,需求发生了变化,当前库无法满足,也许你就会尝试对库源码进行修改,这就违背了开放封闭原则。
3.2 使用扩展函数
扩展函数需要一个前缀,就是接受者类型,通常为类和接口的名称。
This代表的是接收者类型的对象
fun MutableList<Int>.exchange(fromIndex:Int,toIndex:Int){
val temp = this[fromIndex]
this[fromIndex]= this[toIndex]
this[toIndex] = temp
}
对应的Java代码为:
public final class TestMethodKt {
public static final void exchange(@NotNull List $this$exchange, int fromIndex, int toIndex) {
Intrinsics.checkNotNullParameter($this$exchange, "$this$exchange");
int temp = ((Number)$this$exchange.get(fromIndex)).intValue();
$this$exchange.set(fromIndex, $this$exchange.get(toIndex));
$this$exchange.set(toIndex, temp);
}
}
我们可以把扩展函数理解为静态方法,静态方法独立于该类的任务对象,且不依赖类的特定实例,被该类的所有实例共享。
3.3.扩展函数的作用域
通常扩展函数直接定义在一个包内,也就是直接写入到kt文件内。
如果需要再其他包中调用,只需要Import相应的方法即可。
Package com.example.extension
fun MutableList<Int>.exchange(fromIndex:Int,toIndex:Int){
val temp = this[fromIndex]
this[fromIndex]= this[toIndex]
this[toIndex] = temp
}
如果我们也可能将扩展函数定义在一个Class内部统一管理。
class Extends{
fun MutableList<Int>.exchange(fromIndex:Int,toIndex:Int){
val temp = this[fromIndex]
this[fromIndex]= this[toIndex]
this[toIndex] = temp
}
}
转移成Java代码
public final class Extends {
public final void exchange(@NotNull List $this$exchange, int fromIndex, int toIndex) {
Intrinsics.checkNotNullParameter($this$exchange, "$this$exchange");
int temp = ((Number)$this$exchange.get(fromIndex)).intValue();
$this$exchange.set(fromIndex, $this$exchange.get(toIndex));
$this$exchange.set(toIndex, temp);
}
}
这时候发现不是静态方法了。外部无法调用了。这时候只能在该类和该类的子类中可以调用。
3.4 扩展属性
和扩展函数一样,扩展属性本质就是对应Java的静态方法。
扩展函数不能有默认值:因为扩展熟悉没有实际地将成员插入类中,因此对扩展属性来说幕后字段是无效的。
val MutableList<Int>.sumIsEven: Boolean
get() = this.sum() % 2 == 0
转换为Java
public static final boolean getSumIsEven(@NotNull List $this$sumIsEven) {
Intrinsics.checkNotNullParameter($this$sumIsEven, "$this$sumIsEven");
return CollectionsKt.sumOfInt((Iterable)$this$sumIsEven) % 2 == 0;
}
3.5 扩展特殊情况
1. 给静态对象添加扩展函数
class Son {
companion object{
val age = 19
}
}
fun Son.Companion.foo(){
print("age= $age")
}
2. 成员方法优先级高于扩展函数
当类中已经有了一个方法,扩展函数还是当前方法,当调用test1的时候,优先调用成员方法
class Son {
fun test1(){
print("test1")
}
}
fun Son.test1(){
print("extension")
}