我熟悉Java,但我在与Kotlin合作时遇到了困难 .
为了说明我的问题,这里有一些Java代码 . 如果getter发现该字段为NULL,则在返回字段之前初始化该字段 .
package test;
public class InitFieldJava {
private final static String SECRET = "secret";
private String mySecret;
public String getMySecret() {
if(mySecret == null) initMySecret();
return mySecret;
}
private void initMySecret() {
System.out.println("Initializing Secret ....");
mySecret = SECRET;
}
public static void main(String[] args) {
InitFieldJava field = new InitFieldJava();
System.out.println(field.getMySecret());
}
}
我可以在Kotlin做类似的事情 . 我在Kotlin的尝试看起来像这样:
package test
class InitFieldKotlin {
private val SECRET = "secret"
private var mySecret: String? = null
get() {
if (mySecret == null) initMySecret() //Infinite Recursion!!!
return mySecret
}
private fun initMySecret() {
println("Initializing Secret ....")
mySecret = SECRET
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
val field = InitFieldKotlin()
println(field.mySecret)
}
}
}
我的问题是,这导致无限递归:
Exception in thread "main" java.lang.StackOverflowError
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
我很高兴知道自己做错了什么 .
2 回答
尝试在
get()
中使用field
关键字:一般来说,
field
允许直接访问您的值而无需调用get
,几乎与Java示例中的方式相同 . 更多信息可在documentation找到 .您遇到的问题是,当您以这种方式调用您的 property 时,将再次调用getter . 当你调用getter时,会调用另一个getter,依此类推,直到调用StackOverflow .
你可以解决这个问题,如@Google所示,并在getter中使用
field
,而不是属性名称:这样您就不会使用其getter访问该属性 .
但更重要的是: why don't you use a lazy initialization ?如果变量是最终的,而且似乎是,你可以使用一个懒惰的
val
这样,该字段将不再可以为空,因此您无需安全地调用它 . 并且你不会使用样板代码,Kotlin可以为你做这个懒惰的初始化!
关于懒惰的更多例子可以在Kotlin Docs看到