证明问题的最简单的代码是这样的:
Kotlin的主要界面:
interface Base <T : Any> {
fun go(field: T)
}
Run Code Online (Sandbox Code Playgroud)
实现它的抽象类及其方法:
abstract class Impl : Base<Int> {
override fun go(field: Int) {}
}
Run Code Online (Sandbox Code Playgroud)
Java类:
public class JavaImpl extends Impl {
}
Run Code Online (Sandbox Code Playgroud)
它应该可以,但是不能。错误是
类'JavaImpl'必须声明为抽象,或者必须在'Base'中实现抽象方法'go(T)'
如果JavaImpl类位于Kotlin中,它将起作用。同样,如果将T强制转换为String或Integer或任何对象,它也将起作用。但不是Int。
除了使用Integer并抑制Kotlin子类中的数百个警告外,还有什么聪明的解决方案?
更新:创建了问题。
查看字节码我们可以看到,该类Impl基本上生成了以下函数:
public go(I)V
Run Code Online (Sandbox Code Playgroud)
其中参数是原始整数。还会生成一个合成桥接函数 ( go(Object)),但它也会在 Java 端针对此类通用函数生成。
然而,在 Java 方面,仅仅拥有类似的东西是不够的public void go(int field)。现在我们需要那个go(Integer field)- 函数,但它不存在。对我来说,这听起来就像一个互操作问题,可能应该报告并再次链接回此处。实际上已经花了一些时间进行调查,似乎已经存在一些问题:KT-17159和KT-30419,而且KT-5128似乎也与这个问题有关。kotlin 编译器知道如何处理这个问题,并且不需要在类文件中提供任何有关它的进一步信息(即实现的 Kotlin 类知道,它不需要实现类似的东西fun go(field : Int?))。对于 Java 端来说,这样的对应物不存在。我想知道这是否可以通过编译器/字节码很好地解决,或者这是否仍然是一个特定的互操作问题。
处理该问题的一些解决方法(如果这是故意的而不是真正的问题):
添加一个附加函数如下Impl:
fun go(field : Int?) = go(field ?: error("Actually the given field should never be null"))
// or simply:
fun go(field : Int?) = go(field!!)
Run Code Online (Sandbox Code Playgroud)
这样您就不需要实施它。但是,您还会向 Kotlin 端公开该可为 null 的函数,而您可能不希望这样做。
出于该特定目的,以相反的方式执行似乎更方便:在 Java 中声明类和接口并在 Kotlin 端使用它。这样你仍然可以声明类似的东西
abstract class KotlinClass : JavaInterface<Int> {
override fun go(field : Int) { // an IDE might suggest you to use Int? here...
// ...
}
}
Run Code Online (Sandbox Code Playgroud)