【问题标题】:javac source and target optionsjavac 源和目标选项
【发布时间】:2013-03-19 06:33:32
【问题描述】:

我已经看到了Which JDK's distributions can run `javac -source 1.6 -target 1.5`? 中讨论的编译选项。我了解源和目标的各个选项。我不明白为什么源版本高于目标版本。为旧目标编译代码是有意义的。但是在那种情况下,我们为什么不直接使用 -source 我们希望能够在其上运行的最旧目标

【问题讨论】:

    标签: java javac


    【解决方案1】:
    • source:您的源代码编译所需的版本。
    • 目标:您要支持的最旧的 JRE 版本。

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


    来自javacdocumentation:

    交叉编译示例

    以下示例使用 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 选项指定使用 1.6(或 6)版 Java 编程语言编译 OldCode.java。选项-target 1.6 选项确保生成的类文件将与1.6 VM 兼容。请注意,在大多数情况下,-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
    

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

    【讨论】:

      【解决方案2】:

      Java 向后兼容。您使用 -source 选项指定用于编译的 java 版本,并使用 -target 选项指定要支持的最低 java 版本。例如。如果我指定 1.4 的目标,那么我的程序将无法在 java 1.3 或更低版本上运行。有关更多信息,请参阅以下 javac documentation。尤其是关于交叉编译选项

      的部分

      【讨论】:

      • 那么两者兼得有什么意义呢?为什么我们不直接使用最高级别的源版本,然后目标是 1.1 之类的呢?如果java是向后兼容的,那么限制目标版本的意义何在?
      • 利用实现必须提供的各种改进。 Java 1.8 VM 将比 Java 1.0 VM 拥有更多的特性和改进。该语言是向后兼容的,但不是用于运行它的设备。
      • 使用较新的源版本编译以在较旧的目标版本中运行会不会有问题?假设我有一些在 Java 8 中使用 lambdas 的代码......但我的服务器运行 Java 7。那么 -source 1.8 -target 1.7 是否能够让我的代码在 Java 7 中正常运行?
      【解决方案3】:

      Peter Tseng 在编译过程中确实提到了很多要记住的关键点。事实上,即使我曾经也遇到过类似的问题,并且想分享许多问题的根本原因。

      我有一个必须编译并使其兼容的源代码(-source 和 -target)Java '1.8'。代码本身有

      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"/>
      

      【讨论】:

        【解决方案4】:

        JDK1.8 将不再支持 -source 和 -target 小于 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-08
          • 1970-01-01
          • 1970-01-01
          • 2011-01-27
          • 1970-01-01
          相关资源
          最近更新 更多