javac源代码和目标选项

39

我看到了类似于Which JDK's distributions can run `javac -source 1.6 -target 1.5`?这样的编译选项,我理解了源码和目标码的各个选项。但是我不明白为什么源码版本比目标码版本高。将代码编译为旧版本的目标码是有意义的。但是在这种情况下,为什么我们不只使用最旧的目标码的源码选项呢?

4个回答

44
  • 源代码所需的版本进行编译。
  • 您想要支持的最旧的JRE版本。

确保还设置了bootclasspath以确保您的程序可以在较旧的VM上运行。


javac文档中:

交叉编译示例

以下示例使用javac编译可以在1.6 VM上运行的代码。

C\:>javac -source 1.6 -target 1.6 -bootclasspath C:\jdk1.6.0\lib\rt.jar -extdirs "" OldCode.java

-source 1.6选项指定使用Java编程语言版本1.6(或6)来编译OldCode.java。选项-target 1.6确保生成的类文件与1.6虚拟机兼容。请注意,在大多数情况下,-target选项的值是-source选项的值;在本例中,您可以省略-target选项。

您必须指定-bootclasspath选项以指定引导类的正确版本(rt.jar库)。如果没有指定,编译器将生成以下警告:

C:\>javac -source 1.6 OldCode.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6

如果您没有指定正确版本的bootstrap类,编译器将使用旧的语言规则(在本例中,它将使用Java编程语言的1.6版本)与新的bootstrap类结合,这可能会导致类文件不能在较旧的平台上工作(在这种情况下,Java SE 6),因为可能包括对不存在方法的引用。


26

Java具备向后兼容性。您可以使用-source选项指定用于编译的Java版本,使用-target选项指定支持的最低Java版本。例如,如果我指定了目标为1.4,则我的程序将无法在Java 1.3或更低版本上运行。请参阅以下javac 文档以获取更多信息,特别是关于Cross-Compilation Options部分。


7
那么,拥有两者的意义是什么呢?为什么我们不只使用最高级别的源版本,然后将目标设为1.1之类的东西呢?如果Java是向后兼容的,那么限制目标版本的意义是什么? - smac89
3
为了利用各种实现所提供的改进,Java 1.8 VM将拥有比Java 1.0 VM更多的功能和改进。该语言向后兼容,但运行它的设备不是。 - Har
2
使用较新的源代码版本进行编译以在较旧的目标版本中运行是否会出现问题?假设我有一些使用Java 8中的lambda表达式的代码...但我的服务器运行Java 7。那么-source 1.8 -target 1.7是否能够使我的代码在Java 7中正常运行? - evaldeslacasa

4

Peter Tseng提到了许多编译时需要记住的关键点。事实上,我曾经遇到过类似的问题,想分享一下许多问题的根本原因。

我有一个源代码,必须编译并使其与Java '1.8'兼容(-source和-target)。代码本身有以下问题:

  1. 很多商标符号,因此我遇到了无法识别的字符(我不得不调整IntelliJ Idea的编码设置)
  2. 对java.sql.*包进行了许多更改
  3. 使用了大量的第三方库。请饶恕我解释其中的困难和烦恼。

在做了某些更改后,我最终得到了相等数量的JUnit测试用例运行的代码。最终我遇到了java.lang.VerifyError。当我理解这种错误发生在我在不同的库/环境中编译和运行代码时,我感到震惊。

我几乎错过了一个重要的事实,即为了尊重测试必须在隔离环境中运行的事实,JUnit及其测试用例在单独的分叉VM中执行。

<target name="runJunit">
    <junit printonsummary="on" 
           haltonfailure="off"
           fork="true"
           forkmode="once">
        <formatter />
        <batchtest />
        <classpath />
    </junit>
</target>

这显然将作为一个独立的应用程序在执行时被分为一个单独的进程。尽管IDE同步跨越两个进程,但JVM基本上是隔离的。

在Java 1.7之后,Oracle引入了更严格的验证并改变了类格式——包含堆栈映射,用于验证代码是否正确。我看到的异常是因为某些方法没有有效的堆栈映射。我最终尝试了包括很多JVM选项来调整设置,但都无济于事。

<jvmarg value="bootclasspath:{env.JAVA_HOME}\jre\bin\rt.jar" prefix="-X"/>

什么都没用。唯一的解决办法是包含

<jvmarg value=":UseSplitVerifier" prefix="-XX"/>

在Java 1.7中,只允许进行名义字节码验证。由于在Java 1.8中取消了此功能,唯一的选择是使用。
<jvmarg value="-noverify"/>

0

JDK1.8将不再支持源代码和目标代码低于1.6的版本

"c:\Program Files\Java\jdk1.8.0_121\bin\javac.exe" -source 1.3 HelloWorld.java
warning: [options] bootstrap class path not set in conjunction with -source 1.3
warning: [options] source value 1.3 is obsolete and will be removed in a future release
warning: [options] target value 1.4 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
4 warnings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接