我对Scala和Java的交互方式有点困惑。例如,我正在构建一个使用 Scala 2.11.6 版的 Play 应用程序,我需要一个对象来表示日期。
理想情况下,我想使用Java 8中的LocalDate
,但是如果Scala 2.11针对Java JDK 6,这可能吗?
我想更好地了解不同版本的Java如何与Scala一起工作,以及两者之间的关系。
为了回答你的具体问题,如果你用JDK8运行scalac
,那么是的,你可以在Scala 2.11中使用LocalDate
。
至于更普遍的问题,Scala和Java有四种基本的交互方式,它们在版本上是相互分离的(至少在理论上是这样)。
- 在编译时,必须运行某个版本的
java
scalac
- 在编译时,
scalac
读取某个版本的 JVM 字节码 - 在编译时,
scalac
发出某个版本的 JVM 字节码 - 在运行时,
java
(通过scala
脚本)运行发出的 JVM 字节码scalac
。
因此,让我们看看这如何叠加Scala 2.10.5的scalac
,Scala 2.11.x的scalac
,以及即将推出的Scala 2.12.x的scalac
和Java 6,7和8。
- 斯卡拉 2.10.5:
-
scalac
可以由Java 6,7或8运行(由于java
的向后兼容性) -
scalac
可以读取 Java 6 或 7 字节码 - Scala特定的部分,但如果它读取Java 7字节码(例如,因为你使用的是Java 7库),那么你的最终产品中也将包含Java 7字节码,由Java 6字节码调用。 根据您在上一步中的行为,您将拥有纯 Java 6 字节码,然后可以由 Java 6、7 或 8 的
- 或者具有 Java 7 特定功能的字节码,然后只能由 Java 7 或 8 的
java
运行。
scalac
发出Java 6(默认)或7(可选)字节码用于java
运行, -
- Scala 2.11.x:
-
scalac
可以由 Java 6、7 或 8 运行 -
scalac
可以读取 Java 6、7 或 8 字节码(取决于 2.11.x 的版本 x 可以读取和使用或多或少的 Java 8 字节码功能) -
scalac
发出 Java 6(默认)或 Java 7(可选)字节码 - 这里的故事与 2.10.5 相同
-
- Scala 2.12.x:
-
scalac
只能由 Java 8 运行 - (我不确定这里的故事
scalac
是否做出了任何额外的努力来比Java 8的java
向后兼容,例如Java 6兼容性) -
scalac
发出 Java 8 字节码 - Java 8 的
java
必须用于运行生成的二进制文件
scalac
可以读取Java 8字节码和7字节码,凭借Java的向后兼容性 -
只是为了强调理论上这些步骤是完全解耦的,Scala 2.12 的scalac
可以假设由 Scala 2.11 的scalac
编译,以产生一个可以由 Java 6 运行的scalac
,但其结果输出只能由 Java 8 java
运行。
在 Scala 2.11 的情况下,您可以使用 Java 8,只要您向 scalac
提供这些类即可。LocalDate
的唯一特别之处在于它与 Java 平台捆绑在一起,因此如果您在使用 Java 8 中运行scalac
,则无法访问它,而如果您在使用 Java 6 或 7 运行scalac
则无法访问它。如果您使用的是第三方 Java 8 库,则可以将编译后的 JAR 提供给 Scala 2.11.x scalac
,以便使用,无论哪个 Java 版本正在运行scalac
。不过,该字节码可能会进入您自己的发出的 JAR 中,这可能会使下游用户的事情复杂化。
这意味着对于任何非纯 Scala 项目,您必须让您的消费者知道您用于生成的任何 JAR 的 Scala 版本和 Java 版本。如果你的项目是一个库,并且你的消费者使用兼容的 Scala 版本但不兼容的 Java 版本,她/他的代码可以编译,但不会运行。
是不同的:你可以在不同的Java版本(例如1.6,1.7,1.8)上运行相同的Scala版本(比如2.10.5)。
但是,如果您使用特定于 JVM 版本的 JSE 类型,则您的 Scala 代码将无法与以前的 Java 版本一起运行。就好像你用provided
依赖项构建你的 Scala app/lib,而运行时没有实际提供它。
此外,如果根据配置的Java版本scalac
生成的字节码比JRE(用Java 8编译但使用JRE 1.6执行)的字节码更新,则不能将其解释为任何纯Java代码。