kotlin 扩展(扩展函数和扩展属性)

前言

在java中咱们须要扩展一个类的新功能时,通常是继承该类或者使用像装饰者这样的设计模式来实现的。
以下:java

public class Animal {
    protected String name;
    Animal(String name){
        this.name = name;
    }

    public void showName(){
        System.out.print(name);
    }
}
复制代码

咱们想要给这个 类加一个吃东西的功能,这时使用Java继承来实现
实现代码以下:git

public class Cat extends Animal {
    Cat(String name) {
        super(name);
    }
    //新增长吃东西的功能
    public void eat(String food){
        System.out.print(name+":吃了 "+food);
    }

}
复制代码

这样咱们就实现了 吃东西的功能。
而在kotlin咱们不用这样实现了,能够经过叫作 ++扩展++ 的特殊声明来完成。Kotlin 支持 ++扩展函数++ 和 ++扩展属性++。github

1.扩展函数

声明一个扩展函数咱们须要用一个 被扩展的类来做为它的前缀。
公式以下:设计模式

fun 被扩展类名.扩展函数名( 参数 ){app

//实现代码函数

}ui

咱们来实现上面java实现的功能,代码以下:this

fun Animal.eat(food:String){
    print("$name 吃了 $food")
}

复制代码

上面kotlin代码就实现了咱们用java继承实现的新功能,那要怎么调用呢 咱们能够在kotlin中像调用普通的函数来调用这个扩展函数,代码以下:spa

val animal = Animal("cat")
 animal.eat("apple")
复制代码

上面介绍了kotlin中怎么调用扩展函数,那在Java中怎么调用了,代码以下:设计

Animal animal = new Animal("cat");
        //java 中调用kotlin 扩展函数 Aaa 为扩展函数文件名
        AaaKt.eat(animal,"apple");
复制代码

这样咱们就在不用继承该类的状况下增长了 吃东西的新功能。

注意: 咱们能够从上面的java调用中能够看出,扩展并非真正的修改了被扩展类。而只是在kotlin中的调用像是修改了被扩展类。

1.2.扩展是静态解析的

在kotlin中扩展是静态分发的,不是根据接收者类型的虚方法。也就是说调用扩展函数是由调用所在的表达式类型来决定的,而不是由表达式运行时求值结果决定的。例如:

//扩展了 Animal 和Cat Cat 继承 Animal 
    fun Animal.getFood() = "苹果"
    fun Cat.getFood() = "猫粮"
    //在这个方法中 传入类型是 Animal 因此获取到的是"苹果",无论是传入的是Animal 仍是 Animal 的子类 如Cat
    fun printFood(food:Animal){
        print(food.getFood())
    }
    
    fun main(args: Array<String>) {
      val cat = Cat("cat")
      //如我在这传入的是 Cat 可是 输出出来的仍是 苹果
        printFood(cat)
    }
    
复制代码

在这个例子会输出“苹果”,由于咱们在调用扩展函数时只取决于参数 food 的声明类型,该类型是 Animal 类。

若是扩展函数和被扩展类中的成员函数有相同的接收类型、名字和参数,那么这种状况下 ** 老是取成员**。例如:

class Dog {

    fun showName(){
        print("Dog")
    }
}

fun Dog.showName(){
    print("Cat")
}

fun main(args: Array<String>) {
    Dog().showName()
}
    
复制代码

若是咱们调用 Dog 类的 showName(),它将输出“Dog”,而不是“Cat”.

这样是否是很不方便,因此扩展函数能够重载相同名字可是不一样签名成员函数。例如:

class Dog {

    fun showName(){
        print("Dog")
    }
}


fun Dog.showName(name:String){
    print("Cat")
}
fun main(args: Array<String>) {
    Dog().showName("")
}
复制代码

这样咱们调用 showName("")函数,就会输出 “Cat”了。

1.3 可空接受者

扩展函数能够为可空的接收者类型定义扩展。这样的扩展能够在对象变量上调用,即便其值为 null,而且能够在函数体内检测 this == null ,这样就能够在没有检测 null 的时候调用成员函数了,列如:

fun Dog?.toString():String{
    if (this == null) return "null \n"
    return toString()
}

fun main(args: Array<String>) {
    var dog:Dog? = null
    print(dog.toString())
    dog  = Dog()
    print(dog.toString())
}

复制代码

这段代码 第一次打印输出的是 "null \n" 第二次输入的是改对象的地址。

2.扩展属性

与函数相似,Kotlin也支持扩展属性。 例如:

class Snake{
    var aaa = 1
}

var Snake.size:Int
    set(value) {aaa = value}
    get() = aaa +1

fun main(args: Array<String>) {
    val snake = Snake()
    print(snake.size)
    snake.size = 3
    print(snake.size)

}
复制代码

如上例子所示。
**注意:**因为扩展是没有实际将变量成员插入类中,所以对扩展属性来讲幕后字段是无效的。因此扩展属性不能有初始化器,只能显示的提供 getters/setters 定义。

例如:

//错误:扩展属性不能有初始化
val Snake.bbb = 1
复制代码

如上例子是错误的。

3.伴生对象的扩展

咱们知道在kotlin中是没有 static 这个关键字的,那咱们要怎么实现静态变量呢,那就用到了伴生对象,例如:

class Snake{
    var aaa = 1
    companion object {
        var Bbb = 1
    }
}
fun main(args: Array<String>) {
    //这样就达到了Java中静态变量同样的效果了
    Snake.Bbb
}
复制代码

那咱们怎么对伴生对象进行扩展呢,其实也很简单只是比其余扩展中间加了一个 Companion 。如例:

fun Snake.Companion.foo(){...}
复制代码

如上例,我就就定义了一个名为 foo() 的扩展函数,那咱们这调用这个扩展函数了,其实和普通的扩展函数调用方法是同样的,以下例:

Snake.foo()
复制代码

示例地址:github.com/tao11122233…

相关文章
相关标签/搜索