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

Kotlin显式与隐式get()/set()用法及移除get()异常问题解析

Kotlin中显式定义get()/set()属性访问器的原因

Kotlin会为普通属性自动生成默认的get/set访问器,只有当默认逻辑不符合需求时才需要显式自定义,核心适用场景如下:

  • 动态计算属性值:如果属性不需要固定存储值,返回结果依赖其他属性的实时状态,自定义get()可以让属性每次被访问时都基于最新状态计算结果,不会在对象初始化时把值固定死。
  • 拦截赋值操作:自定义set()可以在属性被赋值时做合法性校验、触发联动逻辑(比如状态同步、日志上报),也可以单独修改setter的可见性,比如实现“外部只读、内部可修改”的效果。

对应代码取值异常的根因

移除formattedDate的显式get()定义后,该属性会变成带后端存储字段(backing field)的普通属性,计算逻辑会在对象初始化阶段仅执行一次,结果被固定存到字段里,后续不会更新:

  1. 对象初始化时,主构造参数会先使用定义的默认值,此时publishTime是空字符串"",formattedDate会基于这个空值完成计算。
  2. 如果使用Gson、Moshi等常见JSON反序列化库,实例创建流程是先调用无参构造生成空对象(所有参数取默认值),再通过反射逐个给属性赋值。这种场景下formattedDate会在无参构造阶段就完成空值计算,后续publishTime被反射赋值为正确值时,formattedDate不会重新计算,会一直返回初始化时的空结果。

两种写法的逻辑差异参考如下代码:

data class SampleDomain(
    val publishTime: String = ""
) {
    // 无自定义get的写法:初始化时计算1次,结果固定,后续publishTime变更不影响该值
    // val formattedDate: String = LocalDate.parse(publishTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    //     .format(DateTimeFormatter.ofPattern("MMM. dd, yyyy"))

    // 带自定义get的写法:不生成后端存储字段,每次访问都读取最新publishTime实时计算
    val formattedDate: String
        get() = LocalDate.parse(publishTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME).format(
            DateTimeFormatter.ofPattern("MMM. dd, yyyy")
        )
}

补充规则:如果自定义get()的属性没有初始化赋值、访问器内也没有操作field关键字,Kotlin不会为该属性分配单独的内存空间,访问时直接执行计算逻辑返回结果,没有额外内存开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:51:45