我无法理解Kotlin实际上在做什么:
我的单元测试看起来像这样:
@Test
fun testReadCursorRequest() {
val xml = fromFile()
val parser: ReadCursorRequestParser = ReadCursorRequestParser(xml)
assertEquals(0, parser.status)
assertEquals(134, parser.contacts!!.size)
}
Run Code Online (Sandbox Code Playgroud)
我的解析器看起来像这样
abstract class EnvelopeParser(val xml: String) {
abstract fun parseResponse(response: Element)
init {
parseResponse(xmlFromString(xml))
}
// non-related stuff
}
Run Code Online (Sandbox Code Playgroud)
class ReadCursorRequestParser(xml: String) : EnvelopeParser(xml) {
var contacts: List<AddressBookElementParser> = mutableListOf()
override fun parseResponse(response: Element) {
// here some parsing stuff, fills the contacts-list
println("size is: ${contacts.size}")
}
}
Run Code Online (Sandbox Code Playgroud)
println说size is: 134,单元测试说:java.lang.AssertionError: Expected <134>, actual <0>.
为什么?
正如您在评论parseResponse(...)中所说,从EnvelopeParser构造函数内部调用.
那么当你创建一个实例时发生了什么ReadCursorRequestParser:
分配对象.
该ReadCursorRequestParser构造函数被调用,并调用父类的构造函数立竿见影.
超级构造函数(那个EnvelopeParser)调用parseResponse(...)并因此分配contacts(此时这实际上是一个非空列表).
然后超级构造函数返回,构造函数ReadCursorRequestParser继续.
该ReadCursorRequestParser构造函数分配contacts一次,现在是一个空列表.
原因是每个构造函数首先调用它的超级构造函数(如果有的话),然后才初始化属性并执行init块,超级构造器对类(而不是基类)中声明的状态所做的所有更改都将是由类自己的构造函数覆盖.
此简化示例显示了此行为:( 链接).
最简单的解决方法是将声明更改为contacts类似的
lateinit var contacts: List<AddressBookElementParser>
Run Code Online (Sandbox Code Playgroud)
使用此声明,构造函数将不会重新分配contacts.
但我强烈建议你避免open在构造函数中调用函数,因为如果被覆盖,它们可能(通常会)依赖于尚未初始化的派生类状态,并且它们所做的更改也会被覆盖由派生类构造函数.你甚至可以最终保留一些部分变化,因为它们是在超类状态下完成而另一部分被删除 - 绝对不是你想在日常生活中看到的.
| 归档时间: |
|
| 查看次数: |
81 次 |
| 最近记录: |