Kotlin的又一大特色

  • 给别人的类添加扩展函数和属性
    当我们在一个现有的java或者android项目中,需要添加kotlin的代码,而我们又不能把java等之类的代码全部转重写成kotlin,那会大大降低效率,而kotlin的扩展函数就很好的解决了这个办法。
    例如:我要获取字符串的最后一个字符:

    1
    2
    3
    4
    fun main() {
    println("kotlin".lastChar())
    }
    fun String.lastChar(): Char = this.get(this.length-1)

    结果为

    1
    2
    n
    Process finished with exit code 0

    在上述演示中,String表示接受类型,”kotlin“表示接受者对象,也就是接受类型的具体实例。然后,lastChar就是扩展的函数名,后面则是一个表达式体。
    这样子,就算为莫个类扩展了方法和属性。
    而且,不只是kotlin中,所有java,scale或者Groovy之类的JVM语言编写的都会被编译为java类,也就是都可以为这个类添加扩展。
    而且对于扩展函数而言,他就和其他成员变量一样,可以直接使用类中的方法,也就是默认在ths下。因此可以省略他,如下

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

    但是扩展函数是在类之外定义的函数,他不能破坏类的封装性,所以相对于成员变量而言,扩展函数并不能访问私有或者受保护的变量。

  • 扩展函数也需要从外部导入
    扩展函数并不会自动的在全局生效,尽管智能的IDE会帮你自动导入,但是你仍然需要明白,你必须通过import strings.lastChar类似上述模板的样子来导入方法。

  • 从java中调用扩展函数
    以上述的扩展函数为例

    1
    char c = StringUtilKt.lastChar("JAVA")

    这里,StringUtilKt是指包含这个属性的包名。从java中调用扩展函数时,他就和调用静态方法一样,只是这个接受者对象需要作为第一个参数传递到该方法中。形式如上。

  • 扩展函数不能重写
    因为在通过JVM编译后,他实际上会被转化为静态函数,所以扩展函数重写并没有什么意义,如果重写了该方法,最后调用该方法只取决于是否该对象的静态类型,而不是他的运行时类型
    如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    open class A(val a: String) {
    fun showA() {
    println(a)
    }
    }
    class AA(a:String):A(a){
    }
    fun A.showDoubleA() {
    println(a)
    println(a)
    }
    fun AA.showDoubleA() {
    println(a)
    println(a)
    println(a)
    }
    fun main(){
    val test:A = AA("2")
    test.showDoubleA()
    }
    //输出结果为22
  • 扩展属性
    除了扩展方法外,你也可以扩展属性
    但是同样的,他会在JVM编译器中转化为静态属性,
    如果你定义的是val方法,那么这个属性将是不可变的,你需要自己去定义他的get方法,
    如果用var去定义,那你同时需要定义他的get和set方法。
    因为他没有默认支持的字段,也没有默认的get方法,同理,初始化也不可以,因为没有地方存储初始值
    通过java来调用扩展属性的话,必须使用get和set方法来获取,不能直接操作属性