Init块中使用非final属性问题
与java的构造块不同,Kotlin的init块中可以访问类的成员变量,但这会存在一个很反直觉的坑,而我刚刚趟过……
在Kotlin中类可以有init代码块,其相当于构造函数的一部分,因此可以访问类成员变量。看上去很好的特性,但我最近遇到一个坑:
open class Base(open val name: String) {
init {
println(this@Base.name) // will be null
}
}
open class Derived(override val name: String): Base(name)
如上,看上去构造函数中传递了非空的参数,但在init块中取到的却是空。
原因:这里看上去是访问了父类的成员变量,但实际上它被子类重载,而子类的构造函数执行晚于父类的init代码块。
java中没有属性重载,类似的例子大概是这样:
public abstract class BaseJ {
private final String name;
String getName() {
return name;
}
BaseJ(String name) {
this.name = name;
System.out.println(getName());
}
}
class DerivedJ extends BaseJ {
private final String name;
@Override
String getName() {
return name;
}
DerivedJ(String name) {
super(name);
this.name = name;
}
}
启示:不要在init代码块中访问非final的变量或方法。
StackOverflow上亦有相关讨论。
最后修改于 2025-05-11