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



我尝试从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类实现。zetassketch库中的hyperloglog++实现。

在Java中,我们可以毫无问题地调用重载方法:

但这是正确的,因为Long在Java和Kotlin中具有不同的含义。在Java中,java.lang.LongSomeSet<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会警告你,通常java.lang.Long不应该在Kotlin中使用,但在这种情况下,我认为它没有问题。

作为另一种选择,您不一定需要更改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等效的行为不同)。

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

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

最新更新