扩展函数申明
接收者类型(recievier type)通常是类或接口的名称做前缀。扩展函数体内的this代表的是接收者类型的对象
fun MutableList<Int>.exchange(fromIndex: Int, toIndex: Int) {
val temp = this[fromIndex];// “this”接收者类型的对象
this[fromIndex] = this[toIndex];
this[toIndex] = temp;
}
扩展函数的实现机制
为了更直观分析代码我们把代码转成java对比一下
public static final void exchange(@NotNull List $this$exchange,
int fromIndex, int toIndex) {
Intrinsics.checkParameterIsNotNull($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);
}
从java 代码可以看出,我们可以将扩展函数近似理解为静态方法。熟悉Java的应该知道静态方法的特点:它独立于该类的任何对象,且不依赖类的特定实例,被该类的所有实例共享。
扩展函数的作用域
如果从事java开发的小伙伴都喜欢把一些静态公用的方法放在一个类供调用。如果我们用java的书写方式来管理扩展函数会怎么样?
我们新建一个Extends类 把之前的扩展函数copy过来,在运行看看。发现编译不通过,找不到之前的函数了。这是什么原因呢?还是按照刚才的方法编译成java看看。
public final class Extends {
public final void exchange(@NotNull List $this$exchange,
int fromIndex, int toIndex) {
Intrinsics.checkParameterIsNotNull($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);
}
}
我们看到,exchange方法上已经没有static关键字的修饰了。所以当扩展函数在一个class内部时,我们只能在该类和该类的子类中进行调用。
扩展属性
与函数类似,Kotlin 支持扩展属性:
val List<Int>.lastIndex :Int get() = size - 1;
注意:由于扩展没有实际的将成员插入类中,因此对扩展属性来说[幕后字段]是无效的。这就是为什么扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义
public static final int getLastIndex(@NotNull List $this$lastIndex) {
Intrinsics.checkParameterIsNotNull($this$lastIndex, "$this$lastIndex");
return $this$lastIndex.size() - 1;
}
扩展函数接收器
扩展函数有两个接收器的概念:调度接收者和扩展接收者。
调度方式不同,会影响扩展函数,常见的影响有:
1.如果它是顶级函数或车源成员函数,则不能被覆盖。
2.我们无法访问其接收器的非公共属性。
3.扩展接收器总是被静态调度。