问题
This should be an obvious one but I've not yet found an elegant solution. For various reasons, I need to create an immutable Scala map (scala.collection.immutable.Map from Scala 2.10), but I can only write Java code. How do I do this?
回答1:
Wild guess - here goes nothing:
scala.collection.immutable.Map$.MODULE$.<…, …>empty()
回答2:
At first I was puzzled that just doing the following would fail:
scala.collection.immutable.Map<Integer, String> = scala.collection.immutable.Map$.<Integer, String>empty();
The reason it seemed odd is because I know for a fact that scala generates static forwarders that internally dereference MODULE$ and call the corresponding (non-static) method.
I made some tests, and although what I found is somewhat tangential to the original question, it is still related and good to know.
Say we have the following:
package test
object MyScalaObject {
def empty[A, B]: Map[A, B] = sys.error("TODO")
}
Using javap we can see that a static forwarder is generated:
public class test.MyScalaObject extends java.lang.Object{
public static scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
And indeed we can in java just do the following:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject.<Integer, String>empty();
All is well and nice.
However, if we add a class or trait MyScalaObject that also defines a method with the same signature, no static forwarder is generated by scala (certainly because the JVM does not allow a class to define both a static and non-static method with the same signature). There are probably other different subtle situations that prevent the static forwarders to be generated.
Consider:
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 shows that the static forwarder has indeed disappeared:
public class test.MyScalaObject extends java.lang.Object{
public scala.collection.immutable.Map empty();
public test.MyScalaObject();
}
In this case it means that we have to explictly dereference $MODULE which points to the (unique) instance of the singleton object:
scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject$.MODULE$.<Integer, String>empty();
As it turns out, both the trait scala.collection.immutable.Map and its companion object define a parameterless empty method, so we stumble upon this very issue.
The moral is that while static forwarders are a potentially useful feature, it is also very fragile because the mere fact of modifying a class (in this case adding an empty method in class MyScalaObject) can break the feature, without even touching its companion object itself. It is thus certainly a good idea to always explicitly reference MODULE$ (as in Wilfred Springer's answer) even if it looks less nice and even if the static forwarder is currently present, to prevent potential breakage when updating to a newer version of the library.
来源:https://stackoverflow.com/questions/14365048/how-do-i-create-an-empty-immutable-scala-map-in-java