【问题标题】:`java.lang.StackOverflowError` when accessing Kotlin property访问 Kotlin 属性时的“java.lang.StackOverflowError”
【发布时间】:2019-04-11 16:41:15
【问题描述】:

我从 Packt 的“Programming Kotlin”中获得了这个(人为的)示例,关于使用带有继承的辅助构造函数。

编辑:从答案中可以清楚地看出问题与backing field 有关。但这本书并没有介绍这个想法,只是用了错误的例子。

open class Payment(val amount: Int) 

class ChequePayment : Payment { 
    constructor(amount: Int, name: String, bankId: String) :  super(amount) { 
        this.name = name
        this.bankId = bankId 
    }

    var name: String
        get() = this.name
    var bankId: String
        get()  = this.bankId
} 


val c = ChequePayment(3, "me", "ABC")    
println("${c} ${c.amount} ${c.name}")

当我运行它时会显示此错误。

$ kotlinc -script class.kts 2>&1 | more
java.lang.StackOverflowError
    at Class$ChequePayment.getName(class.kts:10)
    at Class$ChequePayment.getName(class.kts:10)
    at Class$ChequePayment.getName(class.kts:10)

第10行好像是无限递归,怎么解决?

【问题讨论】:

  • 太糟糕了,Packt 的材料包含非工作示例
  • 哎哟。这不是一个好兆头......另外,我知道这是为了示例,但您可能会为此使用主构造函数。
  • 有点,但对于不熟悉字段关键字(或 Kotlin 中的属性而不是字段)概念的新手来说,这个错误是神秘的。这些链接确实有助于澄清这一点。

标签: kotlin


【解决方案1】:

您的代码中有递归:

class ChequePayment : Payment { 
    constructor(amount: Int, name: String, bankId: String) :  super(amount) { 
        this.name = name
        this.bankId = bankId 
    }

    var name: String
        get() = this.name // recursion: will invoke getter of name (itself)
    var bankId: String
        get()  = this.bankId // recursion: will invoke getter of bankId (itself)
} 

如果您的 getter 不需要自定义逻辑,只需将属性保留为:

var name: String
var bankId: String

它们将有一个默认的 getter,它只是返回支持字段的值。

注意:代码可以/应该重构为:

class ChequePayment(amount: Int, var name: String, var bankId: String) : Payment(amount) {
    // ...
}

这使用了主构造函数,并且冗余度要低得多。

【讨论】:

    【解决方案2】:

    要访问支持字段,您必须使用关键字field 而不是this.name,请参阅https://kotlinlang.org/docs/reference/properties.html#backing-fields

    this.name 引用了 getter,它引用了 this.name,这是一个无限递归,正如您已经指出的那样。在代码中:

    var name: String
        get() = field
    var bankId: String
        get()  = field
    

    旁注:Android Studio 和 Idea 会正确地抱怨在这种情况下您不需要 getter。因此,您可以进一步简化:

    var name: String
    var bankId: String
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      • 2015-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多