Kotlin 1.4.30的新特性预览

更多文章可以访问我的博客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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,387评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,845评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,091评论 0 246
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,308评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,662评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,795评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,008评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,466评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,687评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,181评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,531评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,177评论 3 239
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,126评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,862评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,734评论 2 274

推荐阅读更多精彩内容