我该如何让开发者覆盖接口中的两个方法中的其中一个?

移动开发 2026-07-07

我在用Kotlin开发一个库,但需要实现Java与 Kotlin的互操作性。我的接口有一个接收Lambda表达式的方法。它被重载为两个版本:一个接收Kotlin的 lambda,一个接收Java的 Consumer。我该如何让实现者至少覆盖其中一个,以防止递归调用和栈溢出?

interface MyInterface {
    // Java developers MUST override this method
    fun process(callback: Consumer<MyClass>) {
        process(callback::accept);
    }

    // Kotlin developers MUST override this method
    @JvmSynthetic
    fun process(callback: (MyClass) -> Unit) {
        process(Consumer(callback::invoke));
    }
}

解决方案

我认为要实现你想要的效果,唯一比较合理的办法,是定义一个仅在Java中使用的接口来扩展“真实的”接口。这种做法在 gidds 的一个注释中被提及。

例如:

import java.util.function.Consumer;

// The "real" interface
interface MyInterface {

  fun process(callback: (MyClass) -> Unit)
}

// The Java-specific subtype of the "real" interface
interface MyJavaInterface : MyInterface {

  fun process(callback: Consumer<in MyClass>)

  override fun process(callback: (MyClass) -> Unit) {
    process(Consumer(callback))
  }
}

Kotlin代码将实现 MyInterface,并被迫实现该函数的 (MyClass) -> Unit 版本;而Java代码将实现 MyJavaInterface,并被迫实现 Consumer 版本的函数。并且由于 MyJavaInterfaceMyInterface 的子类型,因此前者可以在后者能使用的任何地方使用。不过请注意,这并不能阻止 MyJavaInterface 的实现者覆盖 (MyClass) -> Unit 版本。若要防止这种情况,你需要把 MyJavaInterface 设为一个抽象类,并将该版本的函数声明为final。

否则你也可以尝试实现一个注解处理器,正如 这个注释 by rzwitserloot 所提及的那样。不过,这样就依赖于库的使用者实际使用你的注解处理器。此外,你还需要两份实现:一份给Kotlin,一份给Java。


也就是说,这个思路从一开始就可能有瑕疵吗?我会重新考虑只保留一个接口,并且只包含其中一个函数。表面上我会选择 (MyClass) -> Unit 版本,因为这是一个Kotlin库。从Java的角度来看,它将是一个像其它函数式接口一样的接口,因此可以用lambda表达式或方法引用来实现。然而,正如Louis Wasserman在注释中所指出的,Java代码将被迫返回 Unit.INSTANCE,这并不太符合人体工学。因此,既然你在设计时就把Java用户放在首位,最好只保留 Consumer 版本。

换句话说,最好只有:

import java.util.function.Consumer

interface MyInterface {

  fun process(callback: Consumer<in MyClass>)
}

Kotlin代码仍然可以通过尾随lambda调用 process

fun foo(arg: MyInterface) {
  arg.process {
    // do something...
  }
}

如果你希望让Kotlin实现者像调用其他Kotlin函数类型一样调用回调(使用 callback(arg) 而不是 callback.accept(arg)),那么你可以定义一个运算符扩展函数:

operator fun <T> Consumer<T>.invoke(t: T) = accept(t)

(我不知道标准库,或任何第三方库,是否已经为标准Java函数类型提供了这样的运算符扩展函数。)

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章