Kotlin中的扩展函数

Kotlin可以在不继承一个类的前提下去扩展一个类的新功能,支持扩展函数和扩展属性。扩展函数一般应用于第三方的sdk,或者是你没有办法控制的一些类,可以对这个类添加一些成员变量或者成员方法。

扩展函数

声明一个扩展函数,需要用一个接受这类型也就是被扩展的属性来作为他的前缀。下面代码为File添加一个readText的扩展函数

fun File.readText(charset: Charset = Charsets.UTF_8):String = readBytes().toString(charset)

val file = File("build.gradle")
println(file.readText())

扩展函数是静态解析的

扩展函数不能真正的去修改他们所扩展的类。通过定义一个扩展,并没有在扩展的类中插入新成员,仅仅是可以通过该类去调用这个新函数。扩展函数是静态的给类去添加的,不具备运行时的多态的。下面的代码

open class Animal
class Dog : Animal()

fun Animal.name() = "animal"
fun Dog.name() = "dog"

fun Animal.printName(anim:Animal){
    println(anim.name())
}

fun main(args: Array<String>){
    Dog().printName(Dog())
}

运行main函数最后输出的是

animal

扩展函数会被编译成public static 类型的函数,在编译后扩展函数会多加一个参数,这个参数是扩展的那个类的对象,下面是编译后的代码

   @NotNull
   public static final String name(@NotNull Animal $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
      return "animal";
   }

   @NotNull
   public static final String name(@NotNull Dog $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
      return "dog";
   }

   public static final void printName(@NotNull Animal $receiver, @NotNull Animal anim) {
      Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
      Intrinsics.checkParameterIsNotNull(anim, "anim");
      String var2 = name(anim);
      System.out.println(var2);
   }

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      printName((Animal)(new Dog()), (Animal)(new Dog()));
   }

Dog是被强转成了Animal,实际上在调用的时候调用的是Animal的 name()     

如果一个类定义了一个成员函数与一个扩展函数,而这两个函数又有相同的接受者类型,相同的名字,都适用与给定的参数,这种情况调用成员函数。例如:

class C {
    fun foo() { println("member") }
}

fun C.foo() { println("extension") }

调用C().foo()输出“member”

扩展函数可以重载成员函数

class C {
    fun foo() { println("member") }
}

fun C.foo(i: Int) { println("extension") }

可空接受者

可以为可空的接受者类型定义扩展,这样可以使用可能为空的对象 调用扩展函数

fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}

扩展属性 

kotlin支持扩展属性,由于扩展并没有实际将成员插入类中, 只能通过getters/setters操作

val <T> List<T>.lastIndex: Int
    get() = size - 1

val Foo.bar = 1 // 错误:扩展属性不能有初始化器

伴生对象也可以扩展         

class MyClass {
    companion object { }  // 将被称为 "Companion"
}

fun MyClass.Companion.foo() { …… }

//就像伴生对象的其他普通成员,只需用类名作为限定符去调用他们
MyClass.foo()

分发接受者 扩展接受者 

扩展声明所在的类的实例称为 分发接收者 ;扩展方法调用所在的接收者类型的实例称为 扩展接收者  。对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。

声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。

open class D { }

class D1 : D() { }

open class C {
    open fun D.foo() {
        println("D.foo in C")
    }

    open fun D1.foo() {
        println("D1.foo in C")
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

class C1 : C() {
    override fun D.foo() {
        println("D.foo in C1")
    }

    override fun D1.foo() {
        println("D1.foo in C1")
    }
}

fun main() {
    C().caller(D())   // 输出 "D.foo in C"
    C1().caller(D())  // 输出 "D.foo in C1" —— 分发接收者虚拟解析
    C().caller(D1())  // 输出 "D.foo in C" —— 扩展接收者静态解析
}

                                                                                                                                                                  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值