在Kotlin中使用默认函数实现接口

在Kotlin中使用默认函数实现接口,kotlin,Kotlin,我有一个带有默认实现的Kotlin接口,例如: interface Foo { fun bar(): String { return "baz" } } 在我尝试从Java实现这个接口之前,这是可以的。当我这样做时,它说类需要被标记为抽象类或实现方法bar()。另外,当我尝试实现该方法时,我无法调用super.bar()请参见 评论中有一项建议: 用Java编写接口(使用默认方法),Java和Kotlin类都能正确使用这些默认值 与Java8的早期版本不同,Ko

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

interface Foo {
    fun bar(): String {
        return "baz"
    }
}
在我尝试从Java实现这个接口之前,这是可以的。当我这样做时,它说类需要被标记为抽象类或实现方法
bar()
。另外,当我尝试实现该方法时,我无法调用
super.bar()

请参见

评论中有一项建议:

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


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

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

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

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

编辑

以上解释是基于观点的

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

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


生成可从Java调用的true
default
方法是Kotlin的一项实验性功能

您需要使用
@JvmDefault
注释对方法进行注释:

interface Foo {
    @JvmDefault
    fun bar(): String {
        return "baz"
    }
}
默认情况下,此功能仍处于禁用状态,您需要将
-Xjvm default=enable
标志传递给编译器,它才能工作。(如果需要在Gradle中执行此操作,请参阅)

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

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

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

interface Foo {
    // presumably other stuff
}

fun Foo.bar(): String {
    return "baz"
}
有关它们的更多信息,请参阅

一个值得注意的“抓到”了:

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

简单地说,扩展函数不会执行您从常规多态性中所期望的操作。这意味着此解决方法不能像常规函数那样重写默认函数。如果您试图重写它,您将得到一些奇怪的行为,因为无论何时您显式地处理子类,都会调用“重写”版本,但是当您一般地处理接口时,会调用扩展版本。例如:

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
}
接口MyInterface{
乐趣a()
}
fun MyInterface.b(){
println(“MyInterface.b()默认实现”)
}
类MyInterfaceImpl:MyInterface{
(a){
println(“MyInterfaceImpl.a()”)
}
乐趣b(){
println(“MyInterfaceImpl.b()\”重写\“实现”)
}
}
趣味主线(args:Array){
val inst1:MyInterface=MyInterfaceImpl()
说明1.a()
inst1.b()//调用“default”实现
val inst2:myinterfaceeimpl=myinterfaceeimpl()//也可以执行“val inst2=myinterfaceeimpl()”(类型是推断的)
指令2.a()
inst2.b()//调用“重写”实现
}

这是一个已知的问题,正在这里跟踪:Java8可以有。但是Java7或6呢?这个特性在1.2.50中仍然是实验性的-如果使用Maven,你需要将
1.8
添加到整个pom的
部分,将
-Xjvm default=enable
添加到
kotlin Maven插件的
部分。至少现在正确的参数似乎是
-Xjvm default=enable