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