在这个上下文中,“this”未定义。

12

我该如何解决以下情况?

interface I
class A(i: I)
class C : I, A(this) // << --- 'this' is not defined in this context

简而言之,我想将类实例传递给超类构造函数。
在 Kotlin 中是否可能?

P.S. 所有答案都很好且技术上是正确的。但让我们给出一个具体的例子:

interface Pilot {
   fun informAboutObstacle()
}

abstract class Car(private val pilot: Pilot) {
    fun drive() {
        while (true) {
            // ....
            if (haveObstacleDetected()) {
                pilot.informAboutObstacle()
            }
            // ....
        }
    }
    fun break() {
        // stop the car
    }
}

class AutopilotCar : Pilot, Car(this) { // For example, Tesla :)
    override fun informAboutObstacle() {
        break() // stop the car
    }
}

这个例子看起来并不是太牵强,那么为什么我不能用面向对象友好的语言来实现它呢?

Translated:

这个例子看起来并不是太牵强,那么为什么我不能用面向对象友好的语言来实现它呢?


1
这可能更适合组合而非继承。让你的 C 维护一个 I 的实例,而不是成为它。或者,你可以允许类 A 通过 setter 方法提供其 I,而不是在初始化时提供。 - Craig Otis
如果必须使用继承,您可以使用一个次要的零参数构造函数,并检查是否实现了I接口? - Paul Hicks
我认为你的扩展示例对问题陈述并没有实质性的补充。你仍然有这个不方便的事实,即你将“Car”作为另一个协作者对象引用自身。我没有看到将“Autopilot”建模为“Pilot”和“Car”两者的任何好处。 - Marko Topolnik
2个回答

8
不,JVM上不可能实现这个。只有在超类初始化后才能使用this
来自:

https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.2.4

对于类myClass的实例初始化方法(§2.9.1),它将新的未初始化对象视为本地变量0中的this参数。在该方法调用myClass或其直接超类的另一个实例初始化方法之前,该方法可以对在myClass中声明的字段进行赋值,但是此时禁止使用字节码指令aload 0this推送到堆栈上,因为尚未调用超类构造函数,所以无法将其作为参数传递给超级构造函数。

Kotlin是一种JVM语言,旨在最大程度地与Java代码互操作,并且具有其语言特性的最小开销。虽然Kotlin可以选择以不同的方式编排对象初始化,但这会在混合Java-Kotlin类层次结构中引起问题并增加显着的开销。


2
在面向对象编程语言(如Java, C#Swift)的良好传统中,Kotlin不允许您在调用超类初始化完成之前泄漏this引用。 在您的特殊情况下,您只是存储了该引用,但在略微不同的情况下,超类代码可能会尝试使用接收到的对象,而在此时该对象仍未初始化。
一个具体的例子是,当A是您使用的库中的类且此规则未生效时,请考虑以下情况。您像平常一样传递this,一切都很好。稍后,您将该库更新为较新版本,它恰好将i.toString()添加到其构造函数中。它不知道它实际上正在调用自身上的被覆盖方法。您的toString()实现会观察到所有其不变量被破坏,例如未初始化的vals。
这个设计存在其他问题,不仅仅是您现在遇到的循环初始化依赖。简而言之,类A期望这样:

A and I

但是你却创造出了这个:

C is I

A 依赖于类型为 I 的协作者对象。它不期望自己作为协作者。这可能会导致各种奇怪的错误。例如,您的 C.toString() 可能会委托给 super.toString(),而 A.toString()ACsuper)可能会调用 I.toString(),从而导致 StackOverflowError
从您的问题中我无法确定是否设计了扩展 A,这将使得 C : A 部分正确,但您肯定应该将 AI 分离。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接