如何在Java中创建一个空的不可变Scala映射?
这应该是一个显而易见的问题,但我还没有找到一个优雅的解决方案。由于各种原因,我需要创建一个不可变的Scala映射(Scala.collection.immutable.Map from Scala 2.10),但我只能编写Java代码。我该怎么做?
这应该是一个显而易见的问题,但我还没有找到一个优雅的解决方案。由于各种原因,我需要创建一个不可变的Scala映射(Scala.collection.immutable.Map from Scala 2.10),但我只能编写Java代码。我该怎么做?
疯狂的猜测 - 这里什么都没有:
scala.collection.immutable.Map$.MODULE$.<…, …>empty()
起初我很困惑,仅仅做以下事情就会失败:
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();
一切都很好,很好。但是,如果我们添加一个类或特征,该类或特征也定义了具有相同签名的方法,则scala不会生成静态转发器(当然,因为JVM不允许类定义具有相同签名的静态和非静态方法)。可能还有其他不同的微妙情况阻止生成静态转发器。MyScalaObject
考虑:
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();
事实证明,trait及其伴随对象都定义了一个无参数方法,因此我们偶然发现了这个问题。scala.collection.immutable.Map
empty
寓意是,虽然静态转发器是一个潜在的有用功能,但它也非常脆弱,因为仅仅修改一个类(在这种情况下,在类中添加一个方法)的事实就可以破坏该功能,甚至不需要触及它的伴随对象本身。因此,始终显式引用(如Wilfred Springer的答案)当然是一个好主意,即使它看起来不太好,即使当前存在静态转发器,以防止在更新到较新版本的库时潜在的中断。empty
MyScalaObject
MODULE$