本节书摘来自异步社区《深入理解Scala》一书中的第1章,第1.4节与JVM的无缝集成,作者[美]Josh Suereth,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.4 与JVM的无缝集成
深入理解Scala
Scala的吸引力之一在于它与Java和JVM的无缝集成。Scala与Java有很强的兼容性,比如说Java类可以直接映射为Scala类。这种紧密联系使Java到Scala的迁移相当简单,但在使用Scala的一些高级特性时还是需要小心的,Scala有些高级特性是Java里没有的。在Scala语言设计时已经小心地考虑了与Java无缝交互的问题,用Java写的库,大部分可以直接照搬(as-is)到Scala里。
1.4.1 Scala调用Java
从Scala里调用Java库是透明的,因为Java惯用法直接对应到Scala惯用法。Java类变成Scala类,Java接口变成Scala抽象特质(trait),Java静态成员被加入Scala伪对象(pseudo Scala object)。以上结合Scala的包导入机制和方法访问机制,使Java库感觉就像原生Scala库一样。虽然有过度简化之嫌,但一般情况下是直接就能用。举例来说,我们有个Java类,它有构造器,有一个成员方法和一个静态辅助方法。
现在我们在Scala里用这个Java类。
这种映射非常自然,使用Java类库成为用Scala做开发时很自然的事。除了有这种紧密集成,你通常还能找到Java库的瘦Scala包装(thin Scala wrapper),提供一些Java API无法提供的高级特性。尝试在Java中使用Scala库时,这些特性就变得很凸显。
1.4.2 Java调用Scala
Scala尝试以最简单的方式把其特性映射到Java。大部分Scala特性可以一对一地简单映射为Java特性,比如类、抽象类、方法等。Scala有些相当高级的特性就难以简单的映射了,包括对象、一等函数和隐式转换等。
Scala对象映射到Java
虽然Java的静态(statics)映射为Scala对象,但Scala对象实际上是个单例类(singleton)的实例,在编译时此单例类命名为对象名后加个$符号。这个单例类里有个Module$静态成员,指向其唯一实例。Scala还提供了转发静态方法的能力,这些静态方法位于伴生类里(一个与object同名的类)。虽然Scala本身并没有使用静态方法,但是它们给从Java里调用Scala提供了便利的语法。
Scala函数映射到Java
Scala鼓励使用作为对象的函数(function as object),或称一等函数。到Java1.6为止,Java语言(和JVM虚拟机)都还没有这样的概念。因此Scala创造了函数特质符号(notion of Function traits),一共有23个特质代表0到22个参数的函数。当编译器碰到需要把方法当做函数传递的场景时,就构造一个(参数数量)合适的特质的匿名子类。由于特质无法映射到Java,从Java中传递一等函数到Scala也就很难实现,但也不是完全没办法。
我们在Scala里构造了一个抽象类,这样Java实现起来就比function特质要容易。虽然这稍微简化了Java端的实现,但还是没百分百地简化问题。Java类型系统和Scala对类型的编码中间还是存在不匹配,我们还是需要在调用Scala时对函数类型做强制转换。
所以在组合使用Scala和Java时,使用一等函数和更函数式的编程方法是可能的。但是还存在其他的手段来达到这个目的。这方面更详细的讨论以及其他Java/Scala交互相关的问题请见第10章。如你所见,Scala可以很好地集成现有的Java程序,也可以和Java代码一起使用。Java/Scala交互并非在JVM上跑Scala的唯一好处,JVM本身也带来了巨大的好处。
1.4.3 JVM的优越性
前文曾经提过,Java的很多好处是JVM提供的。通过字节码,可以几乎原封不动地把库分发到很多不同的平台。JVM在很多平台上经过仔细的测试,而且经过了大规模的企业部署。不仅测试完善,还在Java平台的性能方面投入了极大关注。HotSpot编译器能在运行时对代码进行各种优化。用户可以简单地升级JVM,然后立刻体验到性能提升,而无需打补丁或重编译。
HOTSPOT-ING
在JVM上运行Scala的首要好处是HotSpot运行时优化器。它会对程序进行运行时分析,自动对JVM字节码进行调优。Scala运行于JVM上,自然就免费得到了这些优化。JVM每次发布都提升了HotSpot编译器,也就连带着提升了Scala的性能。HotSpot编译器使用了多种技术,包括以下这些。
• 方法内联(Method inlining)。
• 栈替换(On Stack Replacement)。
• 逃逸分析(Escape Analysis)。
• 动态去优化(Dynamic De-optimization)。
方法内联是指HotSpot能够判断是否能在调用点直接把被调的小方法的内容嵌入进去。这是C++里我很喜欢的一项技术,而HotSpot能够动态判断这样做是否对性能有优化。栈替换指HotSpot能够判断一个变量应该放在栈(Stack)里还是堆(Heap)里。我记得用C++的时候一个大问题就是在声明变量的时候应该把它放在栈里还是堆里。现在HotSpot可以为我回答这个问题。逃逸分析是指HotSpot分析判断各种东西是否逸出(escape)了特定作用域。这项技术主要用来在同步方法调用限定于某个作用域时减少锁开销,但也可以用于其他情况。动态去优化是HotSpot的一个关键特性,它有能力判断一个优化是否事实上没有提升性能,然后取消该优化,改用其他优化。以上特性的组合构成了很有吸引力的图景,这就是为什么各种新/旧语言(比如Ruby)都很渴望在JVM上运行。