带和不带getter的Kotlin只读属性

带和不带getter的Kotlin只读属性,kotlin,Kotlin,这些是等价的吗 val foo=somefoooreturningfunction() val foo get()=somefooreurningfunction() 我对文档的理解是这样的,但在我自己的测试中不是这样的 使用get()someFooReturningFunction(),每次访问属性时都会对其求值,如果不使用get(),则只对其求值一次 它们不是等价的。自定义getter实际上是在每个属性访问时进行评估的,与普通函数类似,而没有自定义访问器的val属性在初始化时只评估一次(

这些是等价的吗

  • val foo=somefoooreturningfunction()

  • val foo get()=somefooreurningfunction()

我对文档的理解是这样的,但在我自己的测试中不是这样的


使用get()
someFooReturningFunction()
,每次访问属性时都会对其求值,如果不使用get(),则只对其求值一次

它们不是等价的。自定义getter实际上是在每个属性访问时进行评估的,与普通函数类似,而没有自定义访问器的
val
属性在初始化时只评估一次(实际上存储在JVM平台上的
final
字段中)

这里至少还有一些区别:

  • 如果属性具有自定义getter(或者是
    打开的
    ,因此可能会被自定义getter覆盖),则控制流分析和nullability推断会将其考虑在内,因为无法保证该属性在连续调用时返回相同的值:

    if (someObject.defaultGetterProperty != null) {
        someObject.defaultGetterProperty.let { println(it) } // OK
    }
    

  • 当属性为private时,如果它没有自定义getter,则根本不会生成getter,并且直接访问backing字段。然而,这只是一个实现细节,不值得依赖


否。除了@hotkey的原因之外,这里有一个简单的演示,使用可变属性显示它们何时绝对不相等。TLDR:如果您的属性是使用可变属性计算的,请始终在初始值设定项上使用自定义getter

data class Calculation(val value1: Int, var value2: Int) {
    val sum: Int = value1 + value2
    val sumWithGetter: Int
        get() = value1 + value2
}

val calculation = Calculation(1, 2)
println(calculation.sumWithGetter) // prints 3
println(calculation.sum)           // prints 3

calculation.value2 = 0
println(calculation.sumWithGetter) // prints 1 (correct)
println(calculation.sum)           // prints 3!
data class Calculation(val value1: Int, var value2: Int) {
    val sum: Int = value1 + value2
    val sumWithGetter: Int
        get() = value1 + value2
}

val calculation = Calculation(1, 2)
println(calculation.sumWithGetter) // prints 3
println(calculation.sum)           // prints 3

calculation.value2 = 0
println(calculation.sumWithGetter) // prints 1 (correct)
println(calculation.sum)           // prints 3!