当前位置:  开发笔记 > Android > 正文

Kotlin:超级构造函数中所做的更改将被覆盖

如何解决《Kotlin:超级构造函数中所做的更改将被覆盖》经验,为你挑选了1个好方法。

我无法理解Kotlin实际上在做什么:

我的单元测试看起来像这样:

@Test
fun testReadCursorRequest() {
    val xml = fromFile()
    val parser: ReadCursorRequestParser = ReadCursorRequestParser(xml)
    assertEquals(0, parser.status)
    assertEquals(134, parser.contacts!!.size)
}

我的解析器看起来像这样

abstract class EnvelopeParser(val xml: String) {
    abstract fun parseResponse(response: Element)

    init {
        parseResponse(xmlFromString(xml))
    }

    // non-related stuff
}

class ReadCursorRequestParser(xml: String) : EnvelopeParser(xml) {

    var contacts: List = mutableListOf()     

    override fun parseResponse(response: Element) {
        // here some parsing stuff, fills the contacts-list
        println("size is: ${contacts.size}")
    }
}

println说size is: 134,单元测试说:java.lang.AssertionError: Expected <134>, actual <0>.

为什么?



1> hotkey..:

正如您在评论parseResponse(...)中所说,从EnvelopeParser构造函数内部调用.

那么当你创建一个实例时发生了什么ReadCursorRequestParser:

    分配对象.

    ReadCursorRequestParser构造函数被调用,并调用父类的构造函数立竿见影.

    超级构造函数(那个EnvelopeParser)调用parseResponse(...)并因此分配contacts(此时这实际上是一个非空列表).

    然后超级构造函数返回,构造函数ReadCursorRequestParser继续.

    ReadCursorRequestParser构造函数分配contacts一次,现在是一个空列表.

原因是每个构造函数首先调用它的超级构造函数(如果有的话),然后才初始化属性并执行init块,超级构造器对类(而不是基类)中声明的状态所做的所有更改都将是由类自己的构造函数覆盖.

此简化示例显示了此行为:( 链接).


最简单的解决方法是将声明更改为contacts类似的

lateinit var contacts: List

使用此声明,构造函数将不会重新分配contacts.

但我强烈建议你避免open在构造函数中调用函数,因为如果被覆盖,它们可能(通常会)依赖于尚未初始化派生类状态,并且它们所做更改也会被覆盖由派生类构造函数.你甚至可以最终保留一些部分变化,因为它们是在超类状态下完成而另一部分被删除 - 绝对不是你想在日常生活中看到的.

推荐阅读
惬听风吟jyy_802
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有