Kotlin Getter/Setter引发无限递归:如何使volume外部赋值持久生效?
解决Kotlin中Animal类Volume字段的赋值与计算问题
要实现「默认由weight*height计算volume,外部赋值后保留该值不再重新计算」的需求,核心是用额外的 backing 变量区分「外部赋值」和「默认计算」两种状态,既避免赋值失效,也解决setter递归问题。
方案一:用可空类型的backing变量
class Animal(var weight: Double, var height: Double) { // 可空变量存储外部赋值的volume,null表示未被外部赋值 private var _volume: Double? = null var volume: Double get() = _volume ?: weight * height // 有外部赋值就用赋值的,否则计算 set(value) { _volume = value // 直接给backing变量赋值,避免递归 } }
方案二:用布尔标记+非空backing变量
如果不想用可空类型,也可以加布尔标记区分状态:
class Animal(var weight: Double, var height: Double) { private var _volume: Double = 0.0 private var isVolumeSet = false // 标记是否被外部赋值过 var volume: Double get() = if (isVolumeSet) _volume else weight * height set(value) { _volume = value isVolumeSet = true } }
测试验证
运行以下代码就能看到效果:
fun main() { val dog = Animal(2.0, 3.0) println(dog.volume) // 输出6.0,默认计算值 dog.volume = 20.0 println(dog.volume) // 输出20.0,外部赋值生效 dog.weight = 5.0 // 修改weight println(dog.volume) // 仍然输出20.0,不会重新计算,符合需求 }
原有代码问题解析
- 若直接在getter里写
return weight * height,每次获取volume都会重新计算,外部赋值的结果会被覆盖。 - 若setter里不用backing变量/field,直接写
volume = value,会无限递归调用setter方法,导致栈溢出——这是因为Kotlin属性setter本质是函数,直接赋值属性会再次触发setter。
内容的提问来源于stack exchange,提问作者user1906450
相关产品推荐
相关产品推荐

