子类初始化后,抽象类可以工作吗?

时间:2019-10-28 16:10:09

标签: kotlin

我正在使用的类比这要复杂得多,但我认为这个任意示例同样适用。假设我有一个基础抽象类,它总是想将其Int成员之一foo乘以2。只要它是Int,它实际上并不关心值是什么。另外,假设我们不关心何时发生乘法,只要它发生在构造函数时间附近即可。最后,不允许将foo作为构造函数参数传递。它必须是被子类覆盖的类成员。

abstract class ExampleClass {
    abstract val foo: Int
    init {
        println("Here is foo times 2!: ${foo * 2}")
    }
}

class ChildClass : ExampleClass() {
    override val foo = 5
}

这显然行不通。父类首先被构造,因此在运行时将引发错误,因为该成员尚未实例化。但是根据我的条件,我不介意在子类实例化之后是否进行foo的工作。 父类是否有办法说“我的孩子实例化完成后就做”?还是我只需要让步:

abstract class ExampleClass {
    abstract val foo: Int
    fun bar() {
        println("Here is foo times 2!: ${foo * 2}")
    }
}

class ChildClass : ExampleClass() {
    override val foo = 5
    init {
       bar()
    }
}

我的所有子类都在初始化时调用bar()吗?用这种方式这样做是错误的,因为用foo完成的工作只会发生一次。

2 个答案:

答案 0 :(得分:2)

我相信答案是否定的,这是不可能的。

科特林语言documentation for class initialization这样说:

  

[B]在执行基类构造函数时,尚未初始化在派生类中声明或重写的属性。如果在基类初始化逻辑中使用了这些属性中的任何一个(直接或间接地,通过另一个重写的开放成员实现),则可能导致错误的行为或运行时失败。因此,在设计基类时,应避免在构造函数,属性初始化程序和init块中使用开放成员。

abstract属性本质上是open,因此这里的建议也适用于您的情况:设计类以避免这种情况。

此外,我找不到任何回调样式方法或其他任何方法来“钩住”类初始化逻辑/流并说“初始化完成后执行foo()”。

答案 1 :(得分:0)

如果在子类中使用吸气剂,实际上是有可能的。

<f:format.html parseFuncTSPath="">{some_content}</f:format.html>

尝试here并且使用可变的here