You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中多Elvis运算符未返回默认值却为null的原因

问题解析:Gson实例化后Elvis运算符的不同表现

场景还原

先定义Kotlin数据类:

data class Example(
    @SerializedName("id")
    val id: String,
    @SerializedName("url")
    val url: String,
    @SerializedName("more")
    val more: String = "",
)

用Gson从缺少url字段的JSON字符串实例化对象:

val example1 = Gson().fromJson("{id: 1}", Example::class.java)
val example2 = Gson().fromJson("{id: 2}", Example::class.java)

因为JSON里没有url字段,Gson会通过反射给这两个实例的url赋值为null——这绕过了Kotlin的非空类型检查。

奇怪的现象

执行下面代码时,输出结果是url:null:

val url: String = example1?.url ?: example2?.url ?: "aaaaaaaaaa"
println("url:$url")

但换成直接用.访问字段,却能输出预期的默认值url:aaaaaaaaaa:

val url: String = example1.url ?: example2.url ?: "aaaaaaaaaa"
println("url:$url")

原因拆解

问题出在Kotlin编译器对?.操作符的类型推断,以及Elvis运算符(?:)的编译逻辑:

  • ?.带来的编译器优化:
    example1的编译时类型是Example(非空),所以example1?.url等价于直接用.访问,但编译器会推断这个表达式的类型是String(非空)——也就是默认它不可能返回null。基于这个推断,编译器会跳过Elvis运算符的后续分支,直接取example1?.url的运行时值(也就是null),所以最终结果是null。
  • 直接用.的运行时检查:
    虽然example1.url的编译时类型也是非空String,但Elvis运算符在运行时会直接检查实际值是否为null。当发现example1.url是null时,会依次检查example2.url,最后触发默认值分支,返回"aaaaaaaaaa"。

说白了就是Gson搞出来的运行时null,和编译器基于类型推断做的优化撞了车。

内容的提问来源于stack exchange,提问作者Garfieldmao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:39:59