有没有办法使扩展多态?

gst*_*low 2 java polymorphism inheritance extension-methods kotlin

我有以下无法更改的 java 类

interface Parent...
class Child1Class implements Parent...
class Child2Class implements Parent...
class GrandChild1Class extends Child1Class ...
...
Run Code Online (Sandbox Code Playgroud)

现在我编写 Kotlin 应用程序。

我想向所有层次结构添加一些功能。

fun Parent.foo(){ println("Parent.foo")
Run Code Online (Sandbox Code Playgroud)

但我想要有特殊的行为GrandChild1Class

fun GrandChild1Class.foo(){ println("GrandChild1Class.foo")
Run Code Online (Sandbox Code Playgroud)

但如果我写:

val grandChild1: Parent = GrandChild1Class()
grandChild1.foo()
Run Code Online (Sandbox Code Playgroud)

我看到Parent.foo是因为引用类型

但我希望看到GrandChild1Class.foo

有没有办法实现这种事情的多态行为?

Swe*_*per 5

不会。Kotlin 将扩展函数实现为静态 Java 方法,扩展函数的接收者是 Java 方法的第一个参数。

fun String.foo() { }
Run Code Online (Sandbox Code Playgroud)

变成

public static void foo(String $this$foo) { }
Run Code Online (Sandbox Code Playgroud)

当然,静态方法是静态调度的,所以不存在多态性。

简单的解决方法是仅使用 . 检查类型when

fun Parent.foo() = when(this) {
    is GrandChild1Class -> println("GrandChild1Class.foo")
    // other cases...
    // remember to put "more specific" cases first!
    else -> println("Parent.foo")
Run Code Online (Sandbox Code Playgroud)

JVM 中唯一可以动态分派方法的指令是invokeinferfaceinvokevirtualinvokedynamic。前两个都要求在调用该方法的实例的类/接口中声明该方法,这是扩展方法无法做到的。即在 Kotlin 中声明fun String.foo()不可能foojava.lang.String.

Kotlin 编译器理论上可以使用invokedynamic. 它将找到所有适用的扩展方法,执行一些重载解析,并返回CallSite与它找到的特定扩展方法相对应的方法。在实践中,这需要大量的设计来弄清楚确切的行为应该是什么,以及对编译器进行重大更改,并破坏源代码兼容性。