给别的类添加方法:扩展函数

有时候我们会有想给一个类添加上某些方法,但是我们并没有这个类的添加方法的权限,或者是说,这个类是官方提供给我们的。在java中是不可能实现的了,但是在kotlin中确实可以做到的,这个就是kotlin中的扩展方法。

在java中,我们通常会利用静态方法来书写某些工具类,但是在kotlin中的话,我们就可以利用扩展函数来实现。采用了扩展函数的优势是不需要将当前的对象当做参数传入,就像是调用当前对象的方法一样自然。

定义一个扩展函数

  1. //给String类添加了一个printlnForExtend的扩展方法
  2. fun String.printlnForExtend(){
  3. println(this)
  4. }

把要扩展的类或者接口名称,放到即将添加的函数前面,这个类的名称为接收者类型 。用来调用这个扩展函数的那个对象叫做 接收者对象

Kotlin扩展函数 - 图1

在这个例子中,我们的 String 就是接收者类型,哪个字符串调用这个方法,则该字符串就是接收者对象。我们调用试试看:

fun main(args: Array<String>) {
    "laotie".printlnForExtend()
}

打印结果:
laotie

我们的扩展函数就像是 String 里面的内部方法一样,使用起来感觉很舒适。但是我们需要注意的是:扩展方法不能破坏原有类的封装性,也就是说不能访问到私有或者是受保护的类。

导入扩展函数

一般来说,我们只需要调用就行了,编译器(如Android studio)默认会帮助我们进行扩展函数的导入。那导入这一章节是不是就结束了呢?其实还有点需要提一下的。就是我们可以使用关键字 as 来修改导入的类或者函数的名称:

//将扩展方法的名称改为了print
import net.println.kotlin.chapter5.builtins.printlnForExtend as print

"laotie".print()

在不同的包里面,如果有重名的函数的话,就可以采用这种修改方式。

从java中调用扩展函数

//MainKt是当前扩展方法所在文件的文件名
MainKt.printlnForExtend("laotie");

就是跟静态方法的调用方式是一样的。

不可重写的扩展函数

不论是在java中还是在kotlin中,重写成员函数是一件很平常的事情。但是,不能重写扩展函数。

open class View {
     open fun click(){
         println("我是Viiew")
     }
}

class Button :View() {
    override fun click(){
        println("我是Button")
    }
}
//给View定义一个名叫showOff的扩展方法
fun View.showOff(){
    println(" i am a view")
}
//给Button定义一个名叫showOff的扩展方法
fun Button.showOff(){
    println(" i am a button")
}

fun main(args: Array<String>) {
    val view: View = Button()
    view.click()
    view.showOff()
}

打印结果:
我是Button
i am a view

可以看到上面的例子,我们分别定义了两个类 viewButton ,给 viewButton 都定义了叫做 showOff 的扩展方法。我们在执行打印的时候,定义了一个 Button 的对象,但是 View 类型的,这个对象分别调用了 showOffclick 的方法,从打印结果里面可以看出,click 调用的是子类 Button 的方法,但是 showOff 则还是父类 View 的方法,这就证明了扩展方法是不能被重写的。

扩展属性

声明一个扩展属性

val String.lastChar : Char
    get() = get(length -1)

可以看到,和扩展函数一样,扩展属性也像接收者的一个普通的成员属性一样。这里,必须定义getter 函数,因为没有支持字段,因此没有默认 getter 的实现,同理,初始化也不可以:因为没有地方存储初始值。

上面我们声明的是一个不可变的扩展属性,用的是 val 修饰符修饰的,我们还可以定义一个可变属性:

//给StringBuilder定义了一个名叫lastChar的扩展属性,并实现了getter和setter方法
var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

fun main(args: Array<String>) {
    println("laotie".lastChar)

    var builder = StringBuilder("laotie-")
    builder.lastChar = '+'
    println(builder)
}

打印结果:
e
laotie+

在java中调用扩展属性的话,需要显示的调用 getter 函数。