我有一个带有默认实现的Kotlin接口,例如:
interface Foo {
fun bar(): String {
return "baz"
}
}
在我尝试从Java实现此接口之前,这是可以的。当我这样做时,它表示该类需要标记为抽象或实现方法bar()
。此外,当我尝试实施该方法时,我无法拨打super.bar()
。
答案 0 :(得分:18)
生成可从Java调用的真default
方法是Kotlin 1.2.40的实验性特性。
您需要使用@JvmDefault
注释注释方法:
interface Foo {
@JvmDefault
fun bar(): String {
return "baz"
}
}
默认情况下,此功能仍处于禁用状态,您需要将-Xjvm-default=enable
标志传递给编译器才能生效。 (如果您需要在Gradle中执行此操作,请参阅here)。
答案 1 :(得分:12)
答案 2 :(得分:0)
与早期版本的Java8不同,Kotlin可以在界面中使用默认实现。
将Foo
接口实现到Java类时。 Kotlin隐藏了那些接口方法的实现。如上所述here。
数组在Java平台上与原始数据类型一起使用,以避免装箱/拆箱操作的成本。由于Kotlin隐藏了这些实现细节,因此需要一种解决方法来与Java代码进行交互
这是上面链接中的Arrays特有的,但它也适用于所有类(可能是为了支持早期版本的Java8)。
修改强>
以上解释基于意见。
我遇到的一件事就是主要原因。
Kotlin二进制文件使用java字节码版本1.8编译,接口中没有默认方法。他们面临着解决问题的关键问题。
答案 3 :(得分:0)
如果您知道在任何界面实现中都不会覆盖该功能,您可以使用扩展功能作为解决此问题的不错方法。只需将扩展功能放在与接口相同的文件中(并放在顶层,以便其他文件可以使用它)。
例如,您正在做的事情可以通过以下方式完成:
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
}