“这个”在这方面没有定义
我如何解决以下情况?
interface I class A(i: I) class C : I, A(this) // << --- 'this' is not defined in this context
总之,我想将类实例传递给超类的构造函数。
Kotlin有可能吗?
PS所有的答案都是好的,技术上是正确的。 但是让我们举一个具体的例子:
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 } }
这个例子看起来不太有意思,为什么我不能用面向对象的语言来实现呢?
不,这在JVM上是不可能的。 this
只有在超类被初始化后才可用。
从
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.2.4
类myClass的实例初始化方法(§2.9.1)在局部variables0中将新的未初始化对象视为其参数。在该方法调用myClass或其直接超类的另一个实例初始化方法之前,该方法的唯一操作对此进行分配在myClass中声明的字段。
因此,在调用超类构造函数之前禁止字节码指令aload 0
在堆栈上推送this
。 这就是为什么它不能作为超级构造函数的parameter passing。
Kotlin诞生于JVM语言,旨在最大程度地实现与Java代码的互操作性以及最小的语言function开销。 虽然Kotlin可能选择以不同的方式编排对象初始化,但它会在混合的Java-Kotlin类层次结构中产生问题,并增加大量开销。
在诸如Java , C#或Swift之类的OOP语言的良好传统中,Kotlin不允许在调用超类初始化之前泄漏this
引用。 在你的特殊情况下,你只是存储引用,但在一个稍微不同的情况下,超类代码可能会尝试使用接收的对象,该对象仍然是未初始化的。
作为语言不允许的一个具体例子,考虑一个例子,其中A
是你使用的库中的一个类,这个规则不起作用。 你通过this
像你一样,事情工作正常。 后来你将库更新到一个更新的版本,并且恰巧添加了一些像i.toString()
那样的良性的东西给它的构造函数。 它不知道它实际上正在调用自己重写的方法。 您的toString()
实现会观察所有不variables,例如未初始化的val
。
这种设计会遇到其他问题,而不仅仅是现在正在挣扎的循环初始化依赖。 简而言之, A
类期望:
但相反,你创建这个:
类A
依赖于typesI
的协作者对象。 它不认为自己是合作者。 这可能会带来各种奇怪的错误。 例如,您的C.toString()
可能委托给super.toString()
和A.toString()
( A
是C
的super
)可能调用I.toString()
,导致StackOverflowError
。
我不能说你的问题A
是否被设计用于扩展,这将使得C : A
部分正确,但是你绝对应该把A
解开。