我从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行似乎是无限递归,如何解决?
答案 0 :(得分:6)
您的代码中有一个递归:
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)
}
如果您不需要为自己的吸气剂定制逻辑,只需保留以下属性即可:
var name: String
var bankId: String
他们将有一个默认的getter,它只返回返回后备字段的值。
注意:可以/应该将其重构为:
class ChequePayment(amount: Int, var name: String, var bankId: String) : Payment(amount) {
// ...
}
这使用主要的构造函数,并且冗余度要低得多。
答案 1 :(得分:3)
要访问后备字段,您必须使用关键字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将正确地抱怨您在这种情况下不需要吸气剂。因此,您可以进一步简化:
var name: String
var bankId: String