2 回答
TA贡献1804条经验 获得超7个赞
查看字节码我们可以看到,该类Impl
基本上生成了以下函数:
public go(I)V
其中参数是原始整数。还会生成一个合成桥接函数 ( go(Object)
),但它也会在 Java 端针对此类通用函数生成。
然而,在 Java 方面,仅仅拥有类似的东西是不够的public void go(int field)
。现在我们需要那个go(Integer field)
- 函数,但它不存在。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!!)
这样您就不需要实施它。但是,您还会向 Kotlin 端公开该可为 null 的函数,而您可能不希望这样做。
出于该特定目的,以相反的方式执行似乎更方便:在 Java 中声明类和接口并在 Kotlin 端使用它。这样你仍然可以声明类似的东西
abstract class KotlinClass : JavaInterface<Int> {
override fun go(field : Int) { // an IDE might suggest you to use Int? here...
// ...
}
}
TA贡献1773条经验 获得超3个赞
您可以使用它javap来分析问题,显示已编译的接口和类的成员。
javap基础
public interface Base<T> {
public abstract void go(T);
}
javap 实现
public abstract class Impl implements Base<java.lang.Integer> {
public void go(int);
public void go(java.lang.Object);
public Impl();
}
所以,问题正是@Roland指出的:为了满足接口请求的契约Base,Java编译器需要一个public void go(java.lang.Integer)方法,但Kotlin编译器生成的方法有int作为参数。
如果你用 Java 实现接口,比如
class JI implements Base<Integer> {
@Override
public void go(@NotNull Integer field) {
}
}
javap您可以通过获取来分析其编译版本
爪哇
class JI implements Base<java.lang.Integer> {
org.amicofragile.learning.kt.JI();
public void go(java.lang.Integer);
public void go(java.lang.Object);
}
因此,如果您打算使用 Kotlin 类Impl作为 Java 类的超类,解决方案就是使用<Integer>,而不是<Int>,作为类型参数:Int是一个 Kotlin 类,int由编译器翻译为;Integer是您通常在 Java 代码中使用的 Java 类。
将您的示例更改为
abstract class Impl : Base<Integer> {
override fun go(field: Integer) {}
}
public class JavaImpl extends Impl {
}
JavaJavaImpl类编译时没有错误。
添加回答
举报