美文网首页
Kotlin 1.4.30的新特性预览

Kotlin 1.4.30的新特性预览

作者: Aengus_Sun | 来源:发表于2021-03-02 17:27 被阅读0次

    更多文章可以访问我的博客Aengus | Blog

    Kotlin 1.4.30是Kotlin 1.4的最后一个版本,其中包含了Kotlin 1.5中的即将发布的特性,包括inline value classes的稳定、JVMrecord类的实验性支持以及sealed interface的实验性支持,如果想要体验这些特性,需要特别声明版本:

    compileKotlin {
        kotlinOptions {
            languageVersion = "1.5"
            apiVersion = "1.5"
        }
    }
    

    inline value classes的稳定

    在Kotlin 1.3中inline class已经是Alpha状态,而在1.4.30版本中变为了Beta状态。在Kotlin 1.5中将确定inline classes的概念并为了更一般的特性,将其变为value class,我们将在下面提到。

    inline class允许有一个并且只有一个val属性,编译器会自动将内联类替换为其属性,并且将使用内联类的函数的名称进行修改,如下:

    inline class Color(val rgb: Int)
    
    fun changeBackground(color: Color)
    changeBackground(Color(255))
    
    // 编译后
    fun changeBackground-euwHqFQ(color: Int) 
    changeBackground-euwHqFQ(255) 
    

    修改函数名称的原因是防止由于JVM中类似方法的重载导致方法冲突。若在Java中使用Kotlin中定义的内联类,只能调用其空的构造函数,无法对内联类中包裹的属性进行赋值,但是可以定义接收内联类为参数的方法:

    // Kotlin
    inline class Color(val rgb: Int)
    
    // Java
    Color a = new Color();
    a.getRgb() // OK
    a.setRgb(1) // Error
    

    类消除只有在将内联类传给普通方法的时候才会发生,当传给泛型方法或者将内联类存储在Collection中时并不会立刻进行类消除,这有些类似Java中的装箱,只有在进行使用时才会进行拆箱,这些都是自动的。

    对于Java调用修改JVM name

    从1.4.30开始,可以给调用内联类的方法修改其Java调用时的名字,默认由编译器进行修改以防止Java重载冲突,用法如下:

    // Kotlin declarations
    inline class Timeout(val millis: Long)
    
    val Int.millis get() = Timeout(this.toLong())
    val Int.seconds get() = Timeout(this * 1000L)
    
    @JvmName("greetAfterTimeoutMillis")
    fun greetAfterTimeout(timeout: Timeout)
    
    // Kotlin usage
    greetAfterTimeout(2.seconds)
    
    // Java usage
    greetAfterTimeoutMillis(2000);
    

    @JvmName()不会对Kotlin生效,因为Kotlin传入的类型是内联类。

    初始化代码块

    从1.4.30开始可以对内联类添加init代码块了:

    inline class Name(val s: String) {
        init {
            require(s.isNotEmpty())
        }
    }
    

    注意:内联类的init代码块只有调用构造方法的时候才会调用

    Inline value classes

    Kotlin 1.5为内联类带来更具体的概念并且引入了更多的特性,其语法也变为了value class

    对于JVM来说,内联类是对只有一个参数的类的特别优化。value class代表了更一般的概念并且会带来更多的优化:当前的内联类、Valhalla项目原始类。

    由于内联类是value class的一种优化,所以必须要用和以往不同的方式声明:

    @JvmInline
    value class Color(val rgb: Int)
    

    原来的语法inline class还可以继续使用一段时间,但是在1.5中使用会得到一个警告并且将来会被标记为错误。

    Value classes

    Value class代表了不可变的数据实体,现在(Kotlin 1.5)为了支持inline classvalue class同样也只允许一个参数,但在之后的版本中将可以接收多个只读(val)参数:

    value class Point(val x: Int, val y: Int)
    

    Value class完全用来存储数据,没有”标识符“:===操作符不可以被调用,==操作符会比较其中所有的属性;在Valhalla项目引入到JVM后,没有”标识符“这一特性将允许value class通过JVM原始类型来实现。

    上面的特性也是value class不同于data class的一些点。

    对JVM record类的支持

    Java 14中引入了record class,其目的和Kotlin中的data class类似,都是作为数据的简单存储。

    Java record并不遵循JavaBean的规范,在JavaBean中的Getter方法为getX()getY(),而record class中则变为了x()y()。现在Kotlin 1.4.30中也支持了这种语法,在Kotlin中调用record class和JavaBean类似:

    // Java
    record Point(int x, int y) { }
    // Kotlin
    fun foo(point: Point) {
        point.x // 属性调用
        point.x() // 也可以
    }
    

    同样也可以通过@JvmRecord注解将Kotlin中的data class转为record class来给Java调用,这样生成的Getter方法就变成x()而不是getX()

    @JvmRecord
    data class Point(val x: Int, val y: Int)
    

    需要注意的是@JvmRecord注解只有用JVM 15+的版本去编译Kotlin代码时才能够使用。

    密封接口及密封类提升

    当声明一个类为sealed时,将会限制其子类的继承结构,这将允许when表达式的分支检查。在1.4中,密封类有两个限制:顶层类不能是密封接口;继承密封类的所有的直接子类都必须在同一个文件中。

    Kotlin 1.5移除了这两个限制:可以将接口声明为sealed,子类(包括密封类和密封接口)可以不在同一个文件中(但是需要和父类在相同的包下或者编译单元中)。

    sealed interface Expr
    data class Const(val number: Double) : Expr
    data class Sum(val e1: Expr, val e2: Expr) : Expr
    object NotANumber : Expr
    
    fun eval(expr: Expr): Double = when(expr) {
        is Const -> expr.number
        is Sum -> eval(expr.e1) + eval(expr.e2)
        NotANumber -> Double.NaN
    }
    

    密封接口同样可以限制子类的继承结构,除此之外,另一个用法是禁止外部库实现或继承接口。

    在未来使用JVM支持

    sealed classes预览版支持已经被引入到Java 15中,在将来编译Kotlin sealed classes时会提供JVM的原生支持(可能是JVM 17或此特性稳定后)。在Java中,显式的列出密封类或接口的所有子类:

    // Java
    public sealed interface Expression
        permits Const, Sum, NotANumber { ... }
    

    这些信息将使用新的PermittedSubclasses属性存储在类文件中,JVM会在运行时识别sealed classes并且阻止未授权的子类的扩展。

    将来在使用最新的JVM编译Kotlin时,将启动新的sealed classes的JVM原生支持,编译器会在字节码中生成允许的子类列表来确保JVM支持以及格外的运行时检查:

    // JVM 17+
    Expr::class.java.permittedSubclasses // [Const, Sum, NotANunmber]
    

    在Kotlin中并不用像Java一样声明所有继承的子类,编译器将会根据同包下的所有子类自动生成。

    理论上在旧的JVM版本中也可以定义Kotlin密封接口的Java子类,但是并没有相关的限制,因为旧的JVM并没有相关功能。

    原文地址

    New Language Features Preview in Kotlin 1.4.30

    相关文章

      网友评论

          本文标题:Kotlin 1.4.30的新特性预览

          本文链接:https://www.haomeiwen.com/subject/syjxqltx.html