Scala调用Java,完全没有问题;但是反过来总有那么一点不爽,或者必须要修改。这里是项目中一个真实的案例,拿出来分享一下。
- 类型转换
1
2
3
4
5
| object AsnLoader {
...
def batchLoadFile(files: List[String]): Map[String, AsnModule] = files.foldLeft(Map[String, AsnModule]())((x, y) => x ++ load(y))
...
} |
这里的List是Scala里的类,从Java里面调这个方法是不行的,所以需要弄一个wrapper方法:
1
2
3
| import collection.JavaConversions._
...
def batchLoadFile(files: java.util.List[String]): java.util.Map[String, AsnModule] = batchLoadFile(asScalaBuffer(files).toList) |
虽然asScalaBuffer本身就是个implicit,但是这里仍需要显示调用一下,否则编译器会认为batchLoadFile(file: java.util.List[String])更符合调用匹配规则,结果就变成了无限递归……
Java里面这样调用:
1
| AsnLoader.batchLoadFile(list); |
这样看起来解决问题了,但是Eclipse的Scala插件会报一个莫名其妙的函数签名错误,其实根本就没错,直接maven或者用Intellij都是对的,Eclipse插件太烂或者太老。无奈只好把函数名也一起改了:batchLoadFileJ,这样就可以了。如果还不是很明白,去看看JavaConversions里面的implicit。
把Java的Map转换成Scala的immutale map稍微曲折了些,先转换成mutable map,再调用toMap方法转换成immutable map。
- 构造方法
1
2
3
4
5
| class DefaultTransformer(private val asnModule: AsnModule, private val dependencies: Map[String, AsnModule] = Map.empty,
private val repository: Map[String, AsnModule] = Map.empty,
private val messageHandler: MessageHandler = ConsoleMessageHandler(false)) {
...
} |
这里面的Map都是Scala的Map,所以从Java里不能直接调用,而Scala的构造方法又比较特别,重载的话只能减少参数个数而不能改变类型。这时候就需要companion object上场了。
1
2
3
4
5
6
| object DefaultTransformer {
def apply(asnModule: AsnModule,
dependencies: java.util.Map[String, AsnModule],
repository: java.util.Map[String, AsnModule],
messageHandler: MessageHandler) = new DefaultTransformer(asnModule, dependencies, repository, messageHandler)
} |
Java这样调用:
1
| Transformer transformer = DefaultTransformer.apply(...); |
- Scala的bug
嗯,XML在什么语言里都是让人恶心的东西,即使Scala已经尽力做好了:https://issues.scala-lang.org/browse/SI-4865。