为了账号安全,请及时绑定邮箱和手机立即绑定

通过 Java 扩展 Kotlin 类需要我重新实现已经实现的方法

通过 Java 扩展 Kotlin 类需要我重新实现已经实现的方法

繁华开满天机 2023-08-04 18:56:34
演示该问题的最简单代码是这样的:Kotlin 中的主界面:interface Base <T : Any> {  fun go(field: T)}实现它的抽象类和方法:abstract class Impl : Base<Int> {  override fun go(field: Int) {}}Java类:public class JavaImpl extends Impl {}它应该有效,但事实并非如此。错误是类&ldquo;JavaImpl&rdquo;必须声明为抽象或在&ldquo;Base&rdquo;中实现抽象方法&ldquo;go(T)&rdquo;如果 JavaImpl 类在 Kotlin 中,那么它就可以工作。另外,如果T将 投射到String或Integer或任何物体,它也会起作用。但 Int 则不然。除了使用 Integer 并抑制 Kotlin 子类中的数百个警告之外,还有什么聪明的解决方案吗?
查看完整描述

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...

    // ...

  }

}


查看完整回答
反对 回复 2023-08-04
?
慕容3067478

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类编译时没有错误。


查看完整回答
反对 回复 2023-08-04
  • 2 回答
  • 0 关注
  • 77 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信