Javac选项source和target的作用

前言:最初接触到这两个选项是在学习Maven的时候,需要配置pom.xml文件的maven.compiler.source和maven.compiler.target,当时没有深入了解,只是简单的设置为我当前使用的jdk版本8。没有出现任何问题,也就没有进一步探究。然而,今天在看JVM书籍时,在介绍Class文件内容的部分又看到关于source和target的相关介绍,我觉得是时候进行总结了。

概述

source 指定源代码使用的最高语言特性所属的Java SE版本(同JDK版本)
target 指定Class字节码可以运行的最低虚拟机版本

一 .Javac编译器

语法格式:

javac [options] [sourcefiles]

options 选项,也就是我们编译时使用的参数,例如我们常用的选项-encoding指定字符编码、-classpath指定类加载路径。

source和target是编译器的参数,我们平时并不常用到。

1、source 选项

参考官方文档

-source release (release表示JDK发行的版本号,例如1.8)

Specifies the version of source code accepted.(指定可接受的源文件版本)

The following values for release are allowed:

  • 1.6 / 6 No language changes were introduced in Java SE 6. However, encoding errors in source files are now reported as errors instead of warnings as was done in earlier releases of Java Platform, Standard Edition.
  • 1.7/7 The compiler accepts code with features introduced in Java SE 7.
  • 1.8/8 The compiler accepts code with features introduced in Java SE 8.
  • 9 The compiler accepts code with features introduced in Java SE 9.
  • 10 The compiler accepts code with features introduced in Java SE 10.
  • 11 The default value. The compiler accepts code with features introduced in Java SE 11.

如何理解指定可接受的源文件版本呢?

在可以设置的release部分,有这样一句描述:

The compiler accepts code with features introduced in Java SE ${version}
编译器接受带有某版本Java SE中引入的特性的代码

我觉得最重要的是要理解“accept”一词,查看词典

V-T If a person, company, or organization accepts something such as a document, they recognize that it is genuine, correct, or satisfactory and agree to consider it or handle it.
如果一个人、公司或组织接受某样东西,比如一份文件,他们认为或者识别它是真实的、正确的或令人满意的,并同意考虑或处理它。

Java各个发布版本的语言特性(features),如下图所示(详细信息可参考【Java语言特性】):
在这里插入图片描述
假如,我本地系统上安装了JDK 1.8,我编写的代码并没有使用Java SE 8中提供的语言特性,但是我使用了Java SE 5中提供的语言特性:泛型。这时我编译该代码时可以使用-source 5选项,这时JDK1.8的编译器,就不会检查Java SE 5版本以上提供的语言特性,减少了一些不必要的检查,或许能提高一些编译的性能。(注,并不会降低编译的版本,编译器的版本和JDK一致,网上的关于降低编译器版本的说法是有误的)我们平时在命令行编译文件时,并没有提供source参数,其实,默认使用了和JDK一样的版本,对于我的系统安装了的是JDK1.8,所以参数默认为-source 8,会检查Jave SE 8及以下版本的语言特性。

import java.util.ArrayList;
import java.util.List;

public class Java5 {
    public static void main(String[] args) {
        List<String> words = new ArrayList<String>(); 
    }
}

说专业一点就是,提供与指定发行版的源兼容性

在Windows的命令行窗口下,运行命令:javac,获取关于参数(或者说选项)的信息,如下图所示:

在这里插入图片描述
总结:source选项用于指定源文件使用的最高语言特性,以便让编译器识别并编译与特性相关的代码。source最大不能超过JDK版本(Java SE版本),例如Java SE 8,不可能提供Java SE 9的特性,所以如果你的JDK版本是8,source参数最大只能是8。source默认值和JDK版本相同。

例如,以下Java代码使用了Java SE 8的语言特性lambda表达式,我使用编译时指定-source 7

public class LambdaTest {

    public static void main(String[] args) {
        System.out.println(operate(1, 1, (a, b)->a+b));
    }


    public static int operate(int a, int b, MathOperation mathOperation){
        return mathOperation.operation(a, b);
    }

    interface MathOperation {
        int operation(int a, int b);
    }
}


编译结果:
在这里插入图片描述

2、target选项

参考官方文档

-target release
Generates class files for a specific VM version.

生成特定VM(虚拟机)版本的类文件。 默认值和JDK版本一致。

例如,我的JDK版本是1.8,我的程序没有使用Java SE 8的语言特性(假如使用了Java SE 7的特性),我们公司的系统使用的是JDK 7的虚拟机,我希望编译后的Class文件可以在JDK 7的虚拟机上运行,这是我编译文件时需要指定参数-target 7,当然根据虚拟机的兼容性,在高于target指定版本的虚拟机上都可以运行该Class文件。

Class文件是有版本的,有主版本号和次版本号,例如45.1,主版本号45,次版本号1

JDK 1.1的虚拟机可以运行的Class文件版本45.0~45.65535
JDK 1.2 45~46.65535
JDK 1.3 45~47.65535

JDK 1.7 45~51.65535
JDK 1.8 45~52.65535

Class文件的版本等于JDK版本 减去 1 再加上45。因为JDK1.1的Class文件版本是45.0;

注意,即使我只使用了Java SE 7的语言特性,但是我使用JDK 1.8的编译器, 没有指定target参数(相当于使用了默认值-target 1.8),导致我编译的Class文件的主版本为52,然而JDK 1.7的虚拟机最大只能支持主版本号51的Class文件。

代码如下:

import java.util.ArrayList;

public class GenericTest {
    public static void main(String[] args) {
        ArrayList<String> words = new ArrayList<>();
        words.add("abandon");
    }
}

使用JDK 1.8的编译器进行编译,查看编译的Class文件的主版本号:
在这里插入图片描述

使用JDK 1.7的虚拟机运行该Class文件,发生错误。
在这里插入图片描述
总结:target选项,生成特定VM(虚拟机)版本的类文件。也就是说指定Class文件的版本,由于Class文件和虚拟机版本存在联系,也可以说指定了Class文件可以运行的虚拟机版本。

这两个参数我们平时并不经常用到,因为它主要用户交叉编译,就是说我们的项目由很多个模块组成,开发使用的JDK版本可能并不一致,还要考虑Class文件运行的虚拟机的问题,所以各个模块的source和target可能并不相同。

我们平时学习时,为了出现不必要的错误,将source和target配置为和JDK版本一致即可。

二、应用

以为JDK 1.8为例

1.Maven

pom.xml文件

  <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

2. IDEA

全局配置
在这里插入图片描述
模块配置,不同模块可以有不同配置,用于交叉编译。交叉编译以后用到会补充。
在这里插入图片描述

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Java中,我们可以通过使用不同的编译选项和目标版本来生成不同版本的源代码和目标class文件。下面是一些常用的选项: 1. 生成不同版本的源代码 - -source:指定源代码的版本。例如,-source 1.8 表示使用Java 8的语法编写源代码。 - -target:指定目标版本。例如,-target 1.7 表示生成兼容Java 7的class文件。 2. 生成不同版本的目标class文件 - -bootclasspath:指定引导类路径,即包含标准Java API的jar文件的路径。可以使用这个选项来指定生成class文件时使用的API版本。 - -extdirs:指定扩展类库的路径。可以使用这个选项来指定生成class文件时使用的扩展类库版本。 下面是一个例子,演示如何使用javac编译生成不同版本的源码和目标class: 1. 使用Java 8的语法编写源代码 ``` // MyClass.java public class MyClass { public static void main(String[] args) { System.out.println("Hello, world!"); } } ``` 2. 使用以下命令生成兼容Java 7的class文件: ``` javac -source 1.8 -target 1.7 MyClass.java ``` 这将生成一个名为MyClass.class的文件,该文件可以在Java 7的环境中运行。 3. 使用以下命令生成兼容Java 8的class文件: ``` javac -source 1.8 -target 1.8 MyClass.java ``` 这将生成一个名为MyClass.class的文件,该文件可以在Java 8的环境中运行。 4. 使用以下命令生成使用Java 7的API的class文件: ``` javac -bootclasspath /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar MyClass.java ``` 这将使用Java 7的API编译代码,并生成一个兼容Java 7的class文件。 5. 使用以下命令生成使用Java 8的API的class文件: ``` javac -bootclasspath /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar MyClass.java ``` 这将使用Java 8的API编译代码,并生成一个兼容Java 8的class文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月几时有666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值