“lateinit var 覆盖了 lateinit var”

问题描述

假设我有这样的设置:

abstract class FooTest {

    open lateinit var softAssertions: SoftAssertions

    ... reusable auxiliary functions ...
}
@ExtendWith(SoftAssertionsExtension::class)
class BarTest: Footest(){

    @InjectSoftAssertions
    override lateinit var softAssertions: SoftAssertions

    ... actual test cases ...
    
}

IntelliJ 对 softAssertions 中的 BarTest 给出了一个非常有用的警告:

lateinit var 覆盖了 lateinit var

Yeeeeeeees ..?继续,你的意思是什么?

我最终意识到我在 lateinit var 中的 FooTest 真的应该是一个 abstract val,而不是 - 它消除了警告 - 但即便如此,我想知道......是有什么关于 lateinit var 覆盖 lateinit var 的事情,我应该知道但不知道,IntelliJ 想告诉我但没有?

解决方法

原因描述in the issue which added the inspection

A2 [BarTest 在您的案例中] 的实例将有两个字段用于单个属性,而 A1 [FooTest] 中的一个仍然存在有效地未使用。

...

为什么我们认为可疑只是一个具有 lateinit 属性的案例?我想说的是,任何带有支持字段的属性覆盖另一个带有支持字段的属性的情况都是可疑的。

具有支持字段的属性通常可以具有自定义设置器,因此在某些情况下覆盖它们是有意义的。相反,lateinit 属性从来没有自定义设置器,因此覆盖它们会使被覆盖的属性支持字段始终未使用。

这两个不同的支持字段也可以导致有趣的事情,例如 'isInitialized' property of a lateinit variable is false when it is overridden as a var by another class

添加一个例外是有意义的,其中覆盖属性具有与您的情况类似的注释。

,

基本上它只是警告你,它认为这个覆盖可能不是故意的,因为它看不到任何有用的东西。通常,您不能覆盖变量,但 Kotlin 中的变量是属性(即它们具有 getter 和 setter)。因此,从技术上讲,您正在覆盖 getter/setter,但为什么需要这样做,因为您没有更改它们的实现。

在 Kotlin 中重写属性的一个很好的例子是:

abstract class FooTest {
    open val softAssertions: SoftAssertions
}

然后

@ExtendWith(SoftAssertionsExtension::class)
class BarTest: FooTest(){

@InjectSoftAssertions
override lateinit var softAssertions: SoftAssertions

... actual test cases ...
}

在这种情况下,您通过 var(同时具有 getter 和 setter)覆盖了 val(只有一个 getter)。