Kotlin类之扩展

版权声明:本文为欢乐斗佛原创文章,未经其允许不得转载。 https://blog.csdn.net/qq379454816/article/details/78383951

基础知识

Kotlin提供了一种向已经存在的类中动态扩展功能的能力,Java中我们要实现这样的效果可能需要用到装饰者模式,而在Kotlin中不需要任何的设计模式也不需要继承任何东西,可以直接开干。其提供了扩展函数和扩展属性,今天就来带大家学习这块的知识。


一、扩展函数

将函数名添加一个接受者类型就可以构成一个扩展函数,如下:

   /*突然接到一个任务,需要给Person添加上使用电脑的功能
       因为Person已经存在,所以只能使用扩展功能
        */
    fun Person.useComputer() {//扩展函数
        Toast.makeText(this@MainActivity, "人类学会了使用电脑", Toast.LENGTH_SHORT).show()
    }
Person的代码如下:

/**
 * Created by cracker on 2017/10/29.
 */
open class Person : ISpeaker, IWrite {
    override var lang = "english"
    override fun speaker(info: String) {

    }
    override fun write(info: String): Int {

        return 0
    }
}
可以看到Person类中没有定义useComputer方法,我们使用了扩展函数来给Person添加了一个额外的功能,现在我们可以使用这个额外的功能,如下:

  Person().useComputer()
运行效果如下:


这里我们看到Toast中有这样一行代码:this@MainActivity,因为在扩展函数中this表示扩展函数接受类型,也就是Person类型,所以这里使用了this@表达式,有关this@表达式会在以后的文章中详细介绍。

这里我们只是简单的介绍了一下扩展函数,还有一些需要注意的问题,比如扩展函数可以在哪些地方定义?是否可以在子类中复写?子类和类本身对于扩展函数有什么区别?等等。

扩展函数可以在哪些地方定义?

可以在类本身中定义,也可以在别的类中定义,也可以在顶级位置定义。上面演示的是在别的类中定义,我们也可以在Person类本身中定义,如下:

open class Person : ISpeaker, IWrite {
    override var lang = "english"
    override fun speaker(info: String) {

    }

    override fun write(info: String): Int {

        return 0
    }

    fun Person?.toString() {//这里可以使用一个可为null的Person对象来调用
        if (null == this) return
        Log.d("Person", this.lang)
    }
}
可以看到这里我们使用this关键字代表Person类,并且接受者类型是一个可为空的对象,接受者类型指的是“Person?”。

一般我们会在顶级位置定义扩展,如:

package com.xinxue.kotlindemo
import android.util.Log

 fun Person.flySky() {
    Log.e("Person", "我是在顶级位置定义的函数,所以我能飞天!")
}
 open class Person : ISpeaker, IWrite {

派发接受者及扩展接受者

如果我们在一个的类中定义另一个类的扩展,那么这个扩展会属于很多别的类,比如扩展所在的类和扩展本身类型及其他们的子类。这种情况定义扩展所在的类称为派发接受者,扩展函数目标接受者类型称为扩展接受者,这里目标接受者类型不包括其子类。对于这种情况来说要记住:对于派发接受者扩展是虚拟的,对于扩展接受者来说扩展是静态的。这句话很抽象,我也是理解了很久才明白,网上的说法千篇一律,说的都不明白。其实“虚拟的”说的就是这个扩展函数属于定义扩展函数所在类的成员函数,属于其私生子,可以被覆写,被修改;“静态的”说的是类型在调用函数表达式确定时就已经确定参数的类型,不会因为使用时传入的是其子类型而变为调用的是其子类的函数。如下面:

open class IdMachine {
    open fun Person.idCard() {
        Log.e("kk", "无,无")
    }

    open fun Xiaoming.idCard() {
        Log.e("kk", "原户籍,ID号:4567")
    }

    fun printID(person: Person) {
        person.idCard()
    }
}
定义其子类,覆写其为Person及其子类扩展的方法:

class ShenzhenIdMachine : IdMachine() {
    override fun Person.idCard() {
        Log.e("kk", "深圳籍,ID:无")
    }

    override fun Xiaoming.idCard() {
        Log.e("kk", "深圳籍,ID号:4567")
    }

}
然后我们在别的地方调用printID,调用方式如下:

  IdMachine().printID(Person())
  IdMachine().printID(Xiaoming())
  ShenzhenIdMachine().printID(Person())
  ShenzhenIdMachine().printID(Xiaoming())
运行结果如下:


对于上面的例子,不管我们传入Person或者Xiaoming,其实调用的都是Person的扩展方法,没有调用Xiaoming的扩展方法,这是因为printId中的参数我们定义的是Person类型的,这就是说的对于扩展接受者是静态的,也就是在表达式里就确定了。而我们在ShenzhenIdMachine中覆写了扩展函数,所以后面我们输出的内容变了,这就是说的“虚拟的”也就是属于其成员函数。


二、扩展属性

扩展属性类似于扩展函数,就是在普通的属性前面添加上接受者,如下:

package com.xinxue.kotlindemo

import android.graphics.Color
import android.util.Log

val Person.SkinColor: Int
    get() = Color.YELLOW
和扩展函数一样,属性也可以定义在类中、顶级位置(top_level)、其它类中。需要注意的是扩展属性只能是val类型的,因为其不能有后端域变量。



总结

扩展这块的知识不是特别的多但是还是使用蛮多的,特别是扩展函数。还有一个同伴对象添加扩展函数的功能这里没有谈到,下次学习同伴对象的时候再详细的介绍。Kotlin中函数时一等公民,其与类是平级的,也就是可以直接定义函数到包下面,所以学习函数是最主要的事情,只要学好了函数基本也就掌握了Kotlin了。Kotlin和电脑一样,易懂难精,不要听网上说的三两天就可以学会,深入学习还是长远而具有挑战的。





欢迎关注微信公众号“android教科书”,最新最好的文章第一时间送到手!扫描下面的二维码即可:


阅读更多
换一批

没有更多推荐了,返回首页