覆盖子类型 Kotlin/Java 中的函数类型



我有这个接口:

// Interface for any simulation that is integrated against dt
interface SimulationState {
fun integrate(totalTime: Long, deltaTime: Long) : SimulationState
fun interpolate(alpha: Double, previousState: SimulationState) : SimulationState
fun preRender() : Collection<Pair<Int, Int>>
}

在这种情况下,实现与我的问题无关。问题是我可以覆盖子类型中的函数类型吗?下面是一个无法编译的示例;因此,我提出这个问题的原因。

interface ShipState : SimulationState {
// Still in abstract, just hope I can somehow override the function type...
override fun integrate(totalTime: Long, 
deltaTime: Long,
asteroidVectors: Collection<Pair<Double, Double>>) : SimulationState
}

希望上面不可否认的不编译代码清楚地表明了我的意图。这在Java/Kotlin上可能吗?如果是这样,我将如何去做?

JVM对象结构有一个指向可用方法表的内部指针。当你调用对象的方法时,JVM访问这个表(我们称之为vtable(,如果找到方法,它会执行它。但是,如果在那里找不到方法怎么办?然后它尝试在父类中找到此方法。这些访问可能会在编译期间检测到,这有助于避免在运行时调试时出现非常复杂的问题。

现在,让我们假设您的示例是可能的。你有一个实现ShipState的类,通过它也实现了SimulationState。从接口ShipState(具有 3 个参数的接口(实现方法integrate

但是等等,你的对象仍然是SimulationState类型,对吧?现在,假设您要创建一个模拟集合并以单一方式处理它们:

val simpleSimulation = SimulationStateImpl() //imaginary implementation of base interface
val shipSimulation = ShipSimulationImpl() // again imaginary implementation
val simulations = listOf<SimulationState>(simpleSimulation, shipSimulation)
simulations.forEach { it.integrate(totalTime = 100, deltaTime = 50) }

接下来会发生什么?在第一次迭代中,一切都很好。当您在 JVM 访问simpleSimulation调用integrate时,它是 vtable,找到具有两个参数的integrate实现并调用它。好。

在第二次迭代中,JVM访问对象shipSimulation的vtable。它尝试使用两个参数解析方法integrate,但找不到它。好的,下一步该怎么做?有类似的方法,它有三个参数,我们应该调用它吗?如果是,我们需要传递哪个参数?null?为什么?如果您的类似方法多了 5 个参数,该怎么办?编译器和运行时无法解决此问题,这就是它失败的原因。

就Java/Kotlin OOP而言,你想做的不是override。您只是将新方法添加到新接口,巧合的是,它看起来与另一个非常相似。然而,这种巧合并不意味着它是相同的方法。

请看一下这篇精彩的文章,它以低级的细节解释了主题。

可能你不需要override,而是overload.

如果是,只需从派生接口中删除关键字override

如果需要override(将使用多态性(,则两个函数必须具有相同的签名。

无法覆盖该函数:

(Long, Long) -> SimulationState

带功能:

(Long, Long, Collection) -> Unit

相关内容

最新更新