这应该是显而易见的,但我还没有找到一个优雅的解决方案。由于各种原因,我需要创建一个不可变的Scala映射(来自Scala 2.10的scala.collection.immutable.Map),但我只能编写Java代码。我该怎么做?
答案 0 :(得分:17)
疯狂的猜测 - 这里什么都没有:
scala.collection.immutable.Map$.MODULE$.<…, …>empty()
答案 1 :(得分:2)
起初我很困惑,只是做以下事情会失败:
scala.collection.immutable.Map<Integer, String> = scala.collection.immutable.Map$.<Integer, String>empty();
它看起来很奇怪的原因是因为我知道scala生成静态转发器,在内部取消引用MODULE$
并调用相应的(非静态)方法。
我做了一些测试,虽然我发现的问题与原问题有些相似,但它仍然是相关的,也很有用。
说我们有以下内容:
package test
object MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO")
}
使用javap
我们可以看到生成了一个静态转发器:
public class test.MyScalaObject extends java.lang.Object{
public static scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
事实上,我们可以在java中执行以下操作:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject.<Integer, String>empty();
一切都很好。
但是,如果我们添加一个类或特性MyScalaObject
,它也定义了一个具有相同签名的方法,则scala不会生成静态转发器(当然因为JVM不允许类同时定义静态和非静态)具有相同签名的方法)。可能存在其他不同的微妙情况,无法生成静态转发器。
考虑:
package test
class MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO")
}
object MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO TOO")
}
javap
表明静态转发器确实已经消失了:
public class test.MyScalaObject extends java.lang.Object{
public scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
在这种情况下,它意味着我们必须明确解除引用$MODULE
,它指向单例对象的(唯一)实例:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject$.MODULE$.<Integer, String>empty();
事实证明,特征scala.collection.immutable.Map
及其伴随对象都定义了无参数empty
方法,因此我们偶然发现了这个问题。
道德观点是,虽然静态转发器是一个潜在有用的功能,但它也非常脆弱,因为仅修改类的事实(在这种情况下在类empty
中添加MyScalaObject
方法)可以打破这个功能,甚至没有碰到它的伴侣本身。因此,总是明确地引用MODULE$
(如Wilfred Springer的答案),即使它看起来不那么好,即使静态转发器当前存在,也是一个好主意,以防止潜在的破坏更新到更新版本的库时。