0

我有一个混合的 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 绑定的类型有什么问题?

4

3 回答 3

3

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

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
  }
}

这适用于任何K, V组合。

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)
  }
}

永远不要进行 casts 或 use 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))
于 2013-11-12T10:53:07.760 回答
1

在这种情况下,让函数接受最小公分母可能是一个更好的主意java.util.Map,这样您的 Java 代码就不必费力地使用它。Scala 映射可以通过简单的scala.collection.JavaConversions._.

使用以下 Scala:

def test(map: java.util.Map[String, Character]) = ???

您的 Java 代码可以正常调用该方法:

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

任何其他 Scala 代码都可以JavaConversions用于自动转换:

import scala.collection.JavaConversions._
test(Map.empty[String, Character])
于 2013-11-11T20:43:47.477 回答
-4
object ScalaCode {
    def test(map: AnyRef) {
        if (map.isInstanceOf[java.util.HashMap]) {
            //your code here
        } else if (map.isInstanceOf[scala.collection.Map]) {
            //your code here
        }
     }
}
于 2013-11-11T21:01:45.573 回答