gpt4 book ai didi

java - 在 Scala 中使用 Java 类时出现 "ambiguous reference to overloaded definition"

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:07:52 25 4
gpt4 key购买 nike

我在我的 Scala 中使用了一个 Java 类,它生成 ambiguous reference to overloaded definition .这是解释这个问题的代码。

IComponent.java

package javascalainterop;

import java.util.Map;

public interface IComponent {
public void callme(Map<String, Object> inputMap);
}

组件.java
package javascalainterop;

import java.util.Map;

public class AComponent implements IComponent {
String message;
public AComponent(String message) {
this.message = message;
}

@Override
public void callme(Map inputMap) {
System.out.println("Called AComponent.callme with " + message);
}
}

BComponent.scala
package javascalainterop

import java.util.{Map => JMap}

class BComponent(inputMessage: String) extends AComponent(inputMessage) {
override def callme(inputMap: JMap[_, _]) {
println(s"Called BComponent.callme with $inputMessage")
}
}

组件用户.scala
package javascalainterop

import java.util.{HashMap => JHashMap}

object ComponentUser extends App {
val bComponent = new BComponent("testmessage")
val javaMap = new JHashMap[String, AnyRef]
bComponent.callme(javaMap)
}

当我尝试编译 BComponent.scalaComponentUser.scala编译失败并显示以下消息。
javascalainterop/ComponentUser.scala:8: error: ambiguous reference to overloaded definition,
both method callme in class BComponent of type (inputMap: java.util.Map[_, _])Unit
and method callme in trait IComponent of type (x$1: java.util.Map[String,Object])Unit
match argument types (java.util.HashMap[String,AnyRef])
bComponent.callme(javaMap)
^
one error found

Java 类代表一个我无法控制的库。我考虑过使用反射,但它并不能很好地服务于用例。 super[AComponent].callme也不能解决问题。如何解决这种情况以便代码编译和 AComponent.callme在运行时调用?

最佳答案

已编辑

我已经对这个答案进行了重大编辑,以解决早期的混淆并且更正确。

我认为您正在使用的原始库已损坏,并且没有做它看起来正在做的事情。
IComponent声明一个方法 void callme(java.util.Map<String, Object> inputMap) (相当于 Scala 中的 callme(inputMap: java.util.Map[String, AnyRef]: Unit),而 AComponent声明 void callme(java.util.Map inputMap) (callme(inputMap: java.util.Map[_, _]): Unit 在 Scala 中)。

也就是说,IComponent.callme接受 Java Map其键是 String其值为 AnyRef , 而 AComponent.callme接受 Java Map其键是任何类型,其值是任何类型。

默认情况下,Java 编译器会毫无怨言地接受这一点。但是,如果使用 -Xlint:all 编译选项,Java 编译器将发出警告:

javascalainterop/AComponent.java:12:1: found raw type: java.util.Map
missing type arguments for generic class java.util.Map<K,V>
public void callme(Map inputMap) {

但是,在这种特定情况下,存在比仅仅省略 Map 更大的问题。的类型参数。

因为 AComponent.callme 的编译时间签名方法与 IComponent.callme 的方法不同方法,现在看来 AComponent提供两种不同的 callme方法(一种采用 Map<String, Object> 参数,另一种采用 Map 参数)。然而,同时,类型删除(在运行时删除泛型类型信息)意味着这两种方法在运行时(以及使用 Java 反射时)看起来也相同。所以, AComponent.callme覆盖 IComponent.callme (从而履行 IComponent 接口(interface)的契约(Contract)),同时还对 Acomponent.callme 进行任何后续调用与 Map<String, Object>实例模棱两可。

我们可以如下验证:注释掉 callme BComponent 中的定义并更改 ComponentUser.scala 的内容文件如下:

package javascalainterop

import java.util.{HashMap => JHashMap}

object ComponentUser extends App {
//val bComponent = new BComponent("testmessage")
val javaMap = new JHashMap[String, AnyRef]
//bComponent.callme(javaMap)

// Test what happens when calling callme through IComponent reference.
val aComponent = new AComponent("AComponent")
val iComponent: IComponent = aComponent
iComponent.callme(javaMap)
}

运行时,程序现在输出:

Called AComponent.callme with AComponent

伟大的!我们创建了 AComponent例如,将其转换为 IComponent引用,当我们调用 callme ,它是明确的( IComponent 只有一个名为 callme 的方法)并执行 AComponent 提供的覆盖版本.

但是,如果我们尝试调用 callme 会发生什么?原创 aComponent ?

package javascalainterop

import java.util.{HashMap => JHashMap}

object ComponentUser extends App {
//val bComponent = new BComponent("testmessage")
val javaMap = new JHashMap[String, AnyRef]
//bComponent.callme(javaMap)

// Test what happens when calling callme through each reference.
val aComponent = new AComponent("AComponent")
val iComponent: IComponent = aComponent
iComponent.callme(javaMap)
aComponent.callme(javaMap)
}

哦哦!这一次,我们从 Scala 编译器中得到一个错误,它在类型参数方面比 Java 更严格一些:

javascalainterop/ComponentUser.scala:14:14: ambiguous reference to overloaded definition,
both method callme in class AComponent of type (x$1: java.util.Map[_, _])Unit
and method callme in trait IComponent of type (x$1: java.util.Map[String,Object])Unit
match argument types (java.util.HashMap[String,AnyRef])
aComponent.callme(javaMap)
^

请注意,我们甚至没有看过 BComponent然而。

据我所知,没有办法在 Scala 中解决这种歧义,因为这两个歧义函数实际上是一个且相同的,并且在运行时具有完全相同的签名(使反射也无用)。 (如果有人知道,请随时添加评论!)

由于 Java 比 Scala 更喜欢这种通用的废话,因此您可能需要在 Java 中编写使用此库的所有相关代码。

否则,看起来您唯一的选择是:
  • 报告原始库中的错误(AComponent.callme 应该接受 Map<String, Object> 参数——用 Java 术语来说——不仅仅是 Map 参数),或
  • 实现您自己的 AComponent 版本正常工作,或
  • 使用替代库,或
  • 实现你自己的库。

  • 更新

    再多考虑一下,您也许可以通过一点技巧来实现您想要做的事情。显然,这取决于您要做什么,以及实际 IComponent 的复杂性。和 AComponent类,但您可能会发现更改 BComponent 很有用实现 IComponent , 而使用 AComponent实例在其实现。如果 BComponent不必源自 AComponent (在 BComponent.scala 中):

    package javascalainterop

    import java.util.{Map => JMap}

    class BComponent(inputMessage: String) extends IComponent {

    // Create an AComponent instance and access it as an IComponent.
    private final val aComponent: IComponent = new AComponent(inputMessage)

    // Implement overridden callme in terms of AComponent instance.
    override def callme(inputMap: JMap[String, AnyRef]): Unit = {
    println(s"Called BComponent.callme with $inputMessage")
    aComponent.callme(inputMap)
    }
    }

    关于java - 在 Scala 中使用 Java 类时出现 "ambiguous reference to overloaded definition",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51775674/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com