我有一个带有默认实现的Kotlin接口,例如:
interface Foo {
fun bar(): String {
return "baz"
}
}
Run Code Online (Sandbox Code Playgroud)
在我尝试从Java实现此接口之前,这是可以的.当我这样做时,它表示该类需要被标记为抽象或实现该方法bar().此外,当我尝试实现该方法时,我无法调用super.bar().
zsm*_*b13 21
生成default可从Java调用的真实方法是Kotlin 1.2.40的实验特征.
您需要使用注释注释方法@JvmDefault:
interface Foo {
@JvmDefault
fun bar(): String {
return "baz"
}
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,此功能仍处于禁用状态,您需要将-Xjvm-default=enable标志传递给编译器才能使其正常工作.(如果您需要在Gradle中执行此操作,请参阅此处).
然而,它确实是实验性的.博客文章警告说,未来的设计和实现都可能会发生变化,至少在我的IDE中,尽管编译和工作正常,Java类仍然会因未实现这些方法而出现错误.
Dan*_*cer 12
如果您知道不会在接口的任何实现中覆盖该函数,则可以使用扩展函数作为解决此问题的不错方法。只需将扩展功能放在与界面相同的文件中(并在顶层,以便其他文件可以使用它)。
例如,你正在做的事情可以这样完成:
interface Foo {
// presumably other stuff
}
fun Foo.bar(): String {
return "baz"
}
Run Code Online (Sandbox Code Playgroud)
有关它们的更多信息,请参阅有关扩展函数的文档。
一个值得注意的“陷阱”:
我们想强调的是,扩展函数是静态分派的,即它们不是按接收器类型虚拟的。这意味着被调用的扩展函数由调用该函数的表达式的类型决定,而不是由在运行时计算该表达式的结果的类型决定。
简而言之,扩展函数不会做您对常规多态性所期望的事情。对于此变通方法,这意味着默认函数不能像常规函数一样被覆盖。如果你试图覆盖它,你会得到一些奇怪的行为,因为当你显式地处理子类时将调用“覆盖”版本,但是当你一般地处理接口时将调用扩展版本. 例如:
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
}
Run Code Online (Sandbox Code Playgroud)
从 Kotlin 1.4.0 开始,您可以使用以下编译器标志之一:
-Xjvm-default=all-Xjvm-default=all-compatibility(为了与旧的 Kotlin 代码进行二进制兼容)这将为所有接口启用 JVM 默认方法编译。
如果您想了解如何在 IDE 或 Maven/Gradle 项目中设置这些标志,请查看有关编译器选项的文档。
问题KT-4779跟踪了这方面的进展,其中还包括对当前状态的有用总结。不应再使用注释和较旧的编译器标志@JvmDefault。-Xjvm-default=enable-Xjvm-default=compatibility
| 归档时间: |
|
| 查看次数: |
12774 次 |
| 最近记录: |