Scala函数从Java代码接受Java映射

Scala函数从Java代码接受Java映射,java,scala,collections,map,scala-java-interop,Java,Scala,Collections,Map,Scala Java Interop,我有一个Scala/Java混合项目。我正在尝试编写一个Scala函数,该函数首先接受Scala代码中的Scala映射或Java代码中的Java映射-Java.util.HashMap。 下面是我提出的Scala代码: def test[M <: scala.collection.Map[String, Any] with java.util.HashMap[String, Any]] (m: M): Int = { ??? } 并尝试从Java代码中调用它,如下所示: HashMap

我有一个Scala/Java混合项目。我正在尝试编写一个Scala函数,该函数首先接受Scala代码中的Scala映射或Java代码中的Java映射-Java.util.HashMap。 下面是我提出的Scala代码:

def test[M <: scala.collection.Map[String, Any] with java.util.HashMap[String, Any]] (m: M): Int = { ??? }
并尝试从Java代码中调用它,如下所示:

HashMap m = new HashMap<String, Character>();
m.put("key", 'V');
ScalaCode.test(m);
这给了我一个编译时错误:

[javac] /home/username/test/JavaCode.java:79: error: method test in class ScalaCode cannot be applied to given types;
[javac]                         ScalaCode.test(m);
[javac]                                  ^
[javac]   required: M
[javac]   found: HashMap
[javac]   reason: inferred type does not conform to declared bound(s)
[javac]     inferred: HashMap
[javac]     bound(s): HashMap<String,Object>,Map<String,Object>
[javac]   where M is a type-variable:
[javac]     M extends HashMap<String,Object>,Map<String,Object> declared in method <M>test(M)
编辑:我将作业更改为

HashMap<String, Character> m = new HashMap<String, Character>();
试图平息Java类型推断,没有运气-现在它说:

[javac]   reason: inferred type does not conform to declared bound(s)
[javac]     inferred: HashMap<String,Character>
[javac]     bound(s): HashMap<String,Object>,Map<String,Object>  
编辑:来自java.util.Map的子类型没有帮助:

def test[M <: scala.collection.Map[String, Any] with java.util.Map[String, Any]] (m: M): Int = { ??? }  
产生

[javac]   reason: inferred type does not conform to declared bound(s)
[javac]     inferred: HashMap<String,Character>
[javac]     bound(s): scala.collection.Map<String,Object>,java.util.Map<String,Object>

为M绑定的类型有什么问题?

最好让函数接受最小的公分母,在本例中是java.util.Map,这样java代码就不必跳转使用它。只需导入Scala.collection.JavaConversions即可自动转换Scala映射

使用以下Scala:

def test(map: java.util.Map[String, Character]) = ???
Java代码可以正常调用该方法:

test(new HashMap<String, Character>());

您可以使用JavaConverter来实现这一点:

import scala.collection.JavaConverters._
import java.util.{ HashMap => JMap }
import scala.collection.mutable.{ Map => MMap }
现在要了解更好的方法:

implicit class JavaMutableConverters[K, V](map: MMap[K, V]) extends AnyRef {
  final def asMutableJavaMap: JMap[K, V] = {
    val hash = new JMap[K, V]()
    for ( (k, v) <- map) { hash.put(k, v) }
    hash
  }
}
永远不要强制转换或使用instanceof,在互操作的情况下,经验法则是坚持最低公分母

 val x = new JMap[String, Any]();
 x.put("test1", "test2")

 val y = MMap[String, Any]("test1" -> "test2")

 println(TestMaps.test(x))
 println(TestMaps.test(y))

那真是个坏主意。你不应该鼓励任何人以这种方式绕过类型系统。请注意,如果你在转换过程中使用scala.collection.javaconverter并直接调用asJava和asScala,而不是加载所有这些隐式。我也考虑过提到javaconverter,但是使用了JavaConversions的隐式,因为这种方法提供了他在原始问题中所寻求的那种无缝集成。我使用了JavaConversions。但是它们在函数参数中似乎不起作用,至少当从Java代码调用时,编译器只是说它需要另一种类型。你能举个例子说明如何让它在这里工作吗?隐式转换器在Scala中唯一有效,这就是为什么我建议让你的函数接受java.util.Map-你的java代码可以调用它,而不需要任何额外的步骤,你的Scala客户机只需要从Scala版本导入隐式转换器。非常有用,谢谢。我没有想到要导入JavaConversions.uu在客户端Scala代码中。试用后:只有在映射的类型参数被指定时,才能应用1 toScala def test map:JMap[String,Any]={???};2此函数不接受java.util.HashMap的实例-应为java.util.Map;3更重要的是,它不接受Scala映射。如问题中所述,我需要此函数来接受Java或Scala映射,因此尝试定义类型绑定。不确定这里的重载是什么意思。你能提供一个例子吗?好的,这适用于[String,String]类型的映射,当我放入[String,Any]我需要它时停止工作当我传递Java映射[String,Int]时,它表示测试需要映射[String,Any]。另外,我不想使用这个JavaISH解决方案,定义类型绑定看起来更干净,所以我想了解我在使用它时犯了什么错误。另外,我怎样才能在评论中使用换行符?Double space不起作用。好的,这是可行的,当从Java调用时,我需要将HashMap声明为HashMap,以获得Java对原语的自动包装。我还是更喜欢带有类型参数的类似Scala的解决方案,知道它为什么不起作用吗?这里有没有实现或逻辑的方法?Scala标准库中有两个类,但您需要显式标记对象是Y还是Z。除非Y和Z有一个共同的基类型,否则它不能是任何其他方式,因为有时候你需要知道你可以调用哪些方法。
implicit class JavaMutableConverters[K, V](map: MMap[K, V]) extends AnyRef {
  final def asMutableJavaMap: JMap[K, V] = {
    val hash = new JMap[K, V]()
    for ( (k, v) <- map) { hash.put(k, v) }
    hash
  }
}
object TestMaps {

  def test(map: JMap[String, Any]): JMap[String, Any] = {
    map.put("string", "test")
    map
  }

  def test(map: MMap[String, Any]): JMap[String, Any] = {
    test(map.asMutableJavaMap)
  }
}
 val x = new JMap[String, Any]();
 x.put("test1", "test2")

 val y = MMap[String, Any]("test1" -> "test2")

 println(TestMaps.test(x))
 println(TestMaps.test(y))