Kotlin接口中的默认参数问题?

6
interface Test {

    fun test(message: String, delay: Int =100)
}

class A: Test
{
    override fun test(message: String, delay: Int) {
    }

}

我发现我无法在接口或类中使用 @JvmOverloads

如果我在接口中添加 @JvmOverloads,错误信息为 @JvmOverloads 注释不能用于接口方法,如果我在类中添加 @JvmOverloads,错误信息为 平台声明冲突....

不过,在 Kotlin 文件中,我似乎可以使用默认参数,例如:

var a=A()
a.test("1234")

但是当我在Java文件中使用它时,似乎该方法没有进行重载。

A a=new A();
a.test("123");//Compile error

以下无界面版本可以正常工作。
class A
{
    @JvmOverloads
     fun test(message: String, delay: Int=100) {
    }

}

然后我可以在Java文件中正常使用它。
 A a=new A();
 a.test("123");

当添加接口后如何保持相同的功能性?

2个回答

13

这不是一个bug。 @JvmOverloads注解在抽象方法中无效。

根据Kotlin文档:

通常情况下,如果您编写带有默认参数值的Kotlin函数,则在Java中它只会以完整签名的形式出现,所有参数都存在。如果您希望向Java调用者公开多个重载版本,则可以使用@JvmOverloads注解。

该注解也适用于构造函数、静态方法等。但不能用于抽象方法,包括在接口中定义的方法

来源:https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-generation

为什么? 因为正如我提到的文档所述,@JvmOverloads指示编译器生成一堆Java重载方法,省略每个参数,从最后一个开始。 据我所知,每个重载方法在内部调用具有一个更多参数的方法,并且此附加参数具有默认值。 编辑:请参见@hotkey的评论(此处)

这在抽象方法中不起作用,因为它们没有任何主体。 此外,新的Java接口将具有更多的方法,并且其实现必须实现所有这些方法。 Kotlin接口只有一个方法。


5
一个小修正:每个重载方法内部都调用带有一个更多参数的方法 -- 这是不准确的,相反,对于每个拥有默认参数的函数 foo,还会生成另外一个方法 foo$default,它也接收一个位掩码,指示应该用默认值替换哪些参数。所有由 @JvmOverloads 生成的重载方法也会调用此方法。 - hotkey
感谢@hotkey的澄清。已编辑答案并附上了您的评论链接。 - 3voC
当然可以重载接口方法。你为什么觉得不行呢? - Alexey Romanov
@AlexeyRomanov 你可以定义一个带有重载方法的接口,但是该接口的实现不能重载这些方法。但是,经过一番思考,这里并没有接口实现。我将编辑我的答案。 - 3voC
这个方法不能用于抽象方法,因为它们没有任何实现。此外,新的Java接口将有更多的方法,其实现类必须实现所有这些方法。但是,自从Java 8以来,接口方法不再不能有实现体了。接口中的默认方法已经成为一种常见的方式,而且类只需要实现没有默认实现的方法即可。 - Honza Bednář

0
为了得到相同的结果,您可以在 Kotlin 中创建一个 LegacySupport 类,该类实际上将使用默认参数调用函数,然后您可以仅从此类向 java 类公开函数的返回值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接