【问题标题】:Using default function implementation of interface in Kotlin在 Kotlin 中使用接口的默认函数实现
【发布时间】:2017-10-26 01:46:27
【问题描述】:

我有一个带有默认实现的 Kotlin 接口,例如:

interface Foo {
    fun bar(): String {
        return "baz"
    }
}

在我尝试从 Java 实现这个接口之前,这没问题。当我这样做时,它说该类需要标记为抽象或实现方法bar()。另外,当我尝试实现该方法时,我无法调用super.bar()

【问题讨论】:

标签: kotlin


【解决方案1】:

生成可从 Java 调用的真正的 default 方法是 Kotlin 1.2.40实验性功能。

你需要用@JvmDefault注解来注解方法:

interface Foo {
    @JvmDefault
    fun bar(): String {
        return "baz"
    }
}

此功能默认仍处于禁用状态,您需要将-Xjvm-default=enable 标志传递给编译器才能使其工作。 (如果您需要在 Gradle 中执行此操作,请参阅 here)。

不过,这确实是实验性的。博文警告说,未来设计和实现都可能发生变化,至少在我的 IDE 中,尽管编译和工作正常,Java 类仍然会因未实现这些方法而被标记为错误。

【讨论】:

  • 此功能在 1.2.50 中仍处于试验阶段 - 如果使用 Maven,您需要将 <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> 添加到整个 pom 的 <properties> 部分,并将 <arg>-Xjvm-default=enable</arg> 添加到 <args> 部分kotlin-maven-plugin.
  • 至少现在正确的论点似乎是-Xjvm-default=enable
  • 任何对 Kotlin 有经验/洞察力的人都可以更新这个,告诉我们这个功能是否/何时成为“官方”?据我所知,Kotlin 现在已经达到 1.5.x,the docs for JvmDefault 并没有提到它是实验性的。
【解决方案2】:

请参阅the related issue

cmets中有一个推荐:

用 Java 编写你的接口(使用默认方法),Java 和 Kotlin 类都正确使用这些默认值

【讨论】:

    【解决方案3】:

    如果您知道不会在接口的任何实现中覆盖该函数,您可以使用 扩展函数 作为解决此问题的好方法。只需将扩展函数与接口放在同一个文件中(并放在顶层,以便其他文件可以使用它)。

    例如,您正在做的事情可以这样:

    interface Foo {
        // presumably other stuff
    }
    
    fun Foo.bar(): String {
        return "baz"
    }
    

    有关它们的更多信息,请参阅the docs on extension functions

    一个值得注意的“陷阱”:

    我们想强调的是,扩展函数是静态调度的,即它们不是按接收者类型虚拟的。这意味着被调用的扩展函数由调用函数的表达式的类型决定,而不是由在运行时计算该表达式的结果的类型决定。

    简而言之,扩展函数并不能满足您对常规多态性的期望。对于此解决方法,这意味着默认函数不能像常规函数一样被覆盖。如果你试图重写它,你会得到一些奇怪的行为,因为当你显式处理子类时会调用“重写”版本,但是当你处理接口时会调用扩展版本一般.例如:

    interface MyInterface {
        fun a()
    }
    
    fun MyInterface.b() {
        println("MyInterface.b() default implementation")
    }
    
    class MyInterfaceImpl : MyInterface {
        override fun a() {
            println("MyInterfaceImpl.a()")
        }
    
        fun b() {
            println("MyInterfaceImpl.b() \"overridden\" implementation")
        }
    }
    
    fun main(args: Array<String>) {
        val inst1: MyInterface = MyInterfaceImpl()
        inst1.a()
        inst1.b() // calls the "default" implementation
    
        val inst2: MyInterfaceImpl = MyInterfaceImpl() // could also just do "val inst2 = MyInterfaceImpl()" (the type is inferred)
    
        inst2.a()
        inst2.b() // calls the "overridden" implementation
    }
    

    【讨论】:

      【解决方案4】:

      与早期版本的 Java8 不同,Kotlin 可以在接口中具有默认实现。

      当你在 Java 类中实现 Foo 接口时。 Kotlin 隐藏了那些接口方法的实现。如here所述。

      数组与 Java 平台上的原始数据类型一起使用,以避免装箱/拆箱操作的成本。由于 Kotlin 隐藏了这些实现细节,因此需要一种解决方法来与 Java 代码交互

      这是特定于上面链接中的数组,但它也适用于所有类(可能是为了支持早期版本的 Java8)。

      编辑

      以上解释基于意见。

      我遇到了一件事情,这是主要原因。

      Kotlin 二进制文件是使用 Java 字节码 1.8 版编译的,接口中没有默认方法。他们正面临解决它的关键问题。

      【讨论】:

      • Java8可以有。但是 Java7 或 6 呢?
      猜你喜欢
      • 2021-01-19
      • 1970-01-01
      • 2014-10-01
      • 2023-01-23
      • 2021-10-10
      • 2022-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多