【问题标题】:Can Abstract Class Do Work After Child Class Init?子类初始化后抽象类可以工作吗?
【发布时间】:2019-10-29 01:54:33
【问题描述】:

我使用的类比这更复杂,但我认为这个任意示例也可以。假设我有一个基本抽象类,它总是想将它的一个 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 完成的工作只会发生一次。

【问题讨论】:

    标签: kotlin


    【解决方案1】:

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

    Kotlin 语言 documentation for class initialization 是这样说的:

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

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

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

    【讨论】:

    • 我怀疑是这种情况,否则我已经在其他帖子中提出并回答了这类问题。不过我必须承认,我已经习惯了 Kotlin 似乎能够做任何我想做的事情,我有点惊讶它不能做到这一点!不过没关系,反正我只写了几行代码。
    【解决方案2】:

    这实际上是可能的,如果你在你的子类中使用一个 getter。

    abstract class ExampleClass {
        abstract val foo: Int
        init {
            println("Here is foo times 2!: ${foo * 2}")
        }
    }
    
    class ChildClass : ExampleClass() {
        override val foo
        get() = 5
    }
    
    fun main() {
        val test = ChildClass()
    }
    

    试试here 和可变的here

    【讨论】:

    • 哈哈我很欣赏你的聪明!但在我看来,这个答案有两个问题:1. getter 方法似乎仍然是一种 hack,它会根据实现的不同而产生不一致的行为(除非你可以指出其他情况)和 2. getter 方法适用于简单/小型类和类型,例如我的示例中的 Int 成员,但这种方法不适用于我需要一致引用的非静态成员。例如,如果 foo 是一个 MutableList<Int> 并且会发生变化,那么这个方法就会崩溃。
    • 仍然有可能,如果您创建另一个使用 foo 获得的可变变量。但是该变量必须可以为空,并且您的 getter 必须提供默认值。在这种情况下,最好让你的 getter 发送一个列表而不是一个可变的。我同意这仍然是一个 hack。
    • 哦,好吧,这很聪明。我希望我能说我推荐它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 2013-12-30
    • 2018-02-06
    相关资源
    最近更新 更多