如何解决从Kotlin调用泛型重载Java类的重载解析二义性

w51jfk4q  于 2023-04-07  发布在  Kotlin
关注(0)|答案(2)|浏览(194)

我尝试从Kotlin调用一个自定义Java集合,它以这种方式实现了一个add(long value)方法:

public class SomeSet<T> {

    public void add(int value) {  }

    public void add(long value) {  }

    public void add(T value) {   }
}

在Java中,我们可以调用重载方法而不会有任何问题:

SomeSet<Long> set = new SomeSet<Long>();
set.add(1);
set.add(1L);

但在Kotlin中,这似乎是不可能的:

val set = SomeSet<Long>()
set.add(1 as Int)
set.add(1L) // ⚡ Overload resolution ambiguity
set.add(1L as Long) // ⚡ Overload resolution ambiguity

完整编译错误:

Overload resolution ambiguity. All these functions match.
public open fun add(value: Long): Unit defined in de.itscope.platform.producttracking.test.SomeSet
public open fun add(value: Long!): Unit defined in de.itscope.platform.producttracking.test.SomeSe

我已经检查了建议,对于一个很可能的问题:
Kotlin:当Java库同时具有原始类型和装箱类型的重载时,我该怎么办?
但这在这里没有帮助,因为这个泛型重载。
这不是学术示例。这是com.google.zetasketch.HyperLogLogPlusPlus类的实现方式。来自ZetaSketch库的HyperLogLog++实现。

eh57zj3b

eh57zj3b1#

在Java中,我们可以调用重载方法而不会有任何问题:
但这只是因为Long在Java和Kotlin中有不同的含义。在Java中它是java.lang.Long,而SomeSet<Long>有方法add(long value)add(java.lang.Long value)。没有冲突!而Kotlin的kotlin.Long更接近Java的long,因此SomeSet<kotlin.Long>有两个方法接受kotlin.Long。所以你的工作Java示例的等效内容是

val set = SomeSet<java.lang.Long>()
// if you want to call add(long)
set.add(1L)
// if you want to call add(T)
set.add(1L as java.lang.Long)  // or java.lang.Long(1L)

Kotlin会警告你通常不应该在Kotlin中使用java.lang.Long,但在这种情况下,我认为这是正确的。
作为替代方案,您不一定需要更改set变量本身的类型,只需在想要调用该方法时对其进行强制转换:

val s = SomeSet<Long>()
// if you want to call add(long)
(s as SomeSet<*>).add(1L)
// if you want to call add(T)
(s as SomeSet<Any>).add(1L as Any)

Playground(我还没有用Java中实际定义的SomeSet进行测试,但我不希望Kotlin等价物的行为有所不同)。

fdx2calv

fdx2calv2#

我发现调用add函数的唯一方法是,将Any设置为泛型类型:

val set: SomeSet<*> = SomeSet<Any>()
set.add(1)
set.add(1L)

相关问题