corejava11(4.8 JAR文件)

4.8 JAR文件

打包应用程序时,您希望给用户一个单独的文件,而不是一个由类文件填充的目录结构。Java归档(JAR)文件是为此目的而设计的。JAR文件可以包含类文件和其他文件类型,如图像和声音文件。此外,JAR文件使用熟悉的zip压缩格式进行压缩。

4.8.1 创建JAR文件

使用jar工具生成JAR文件。(在默认的JDK安装中,它在jdk/bin目录中。)生成新JAR文件的最常见命令使用以下语法:

jar cvf jarFileName file1 file2 . . .

例如:

jar cvf CalculatorClasses.jar *.class icon.gif

通常,jar命令的格式如下:

jar options file1 file2 . . .

表4.2列出了jar程序的所有选项。它们与UNIX tar命令的选项类似。

表4.2 jar程序选项

选项描述
c创建新的或空的归档并向其中添加文件。如果指定的任何文件名是目录,jar程序将递归地处理它们。
C临时更改目录。例如,
jar cvf jarFileName.jar -C classes *.class
更改classes子目录以添加类文件。
e在清单中创建入口点(见4.8.3节)
f将JAR文件名指定为第二个命令行参数。如果缺少此参数,jar将把结果写入标准输出(创建JAR文件时)或从标准输入(提取或制表jar文件时)读取结果。
i创建索引文件(用于加快大型归档中的查找)。
m向JAR文件添加清单。清单是对归档内容和来源的描述。每个归档都有一个默认清单,但是如果您想验证归档的内容,可以提供自己的清单。
M不为条目创建清单文件。
t显示目录的内容。
u更新现有的JAR文件。
v生成详细输出。
x提取文件。如果提供一个或多个文件名,则只提取这些文件。否则,将提取所有文件。
0存储的时候不用ZIP压缩

您可以将应用程序和代码库打包成JAR文件。例如,如果您想在Java程序中发送邮件,则使用一个打包在javax.mail.jar文件中的库。

4.8.2 清单

除了类文件、图像和其他资源之外,每个JAR文件都包含一个清单文件,描述了归档的特殊特性。

清单文件名为MANIFEST.MF,位于JAR文件的特殊META-INF子目录中。最低限度的合法声明很无聊,只是

Manifest-Version: 1.0

复杂清单可以有更多条目。清单条目被分为多个部分。清单中的第一部分称为主部分。它适用于整个JAR文件。后续条目可以指定命名实体的属性,如单个文件、包或URL。这些条目必须以名称条目开头。各部分用空行分隔。例如:

Manifest-Version: 1.0
lines describing this archive
Name: Woozle.class
lines describing this file
Name: com/mycompany/mypkg/
lines describing this package

要编辑清单,请将要添加到清单的行放入文本文件。然后运行

jar cfm jarFileName manifestFileName . . .

例如,要使用清单生成新的JAR文件,请运行

jar cfm MyArchive.jar manifest.mf com/mycompany/mypkg/*.class

要更新现有JAR文件的清单,请将添加的内容放入文本文件中,并使用诸如

jar ufm MyArchive.jar manifest-additions.mf

注意

参阅https://docs.oracle.com/javase/10/docs/specs/jar/jar.htm
获取更多关于JAR和清单文件格式的更多信息

4.8.3 可执行JAR文件

可以使用jar命令的e选项指定程序调用的入口点,在调用Java程序启动程序时,您通常会指定该类的入口点:

jar cvfe MyProgram.jar com.mycompany.mypkg.MainAppClass files to add

或者,您可以在清单中指定程序的主要类,包括这种格式的语句

Main-Class: com.mycompany.mypkg.MainAppClass

不要在主类名中添加.class扩展名。

小心

清单中的最后一行必须以换行符结尾。否则,将无法正确读取清单。生成只包含Main-Class行而不包含行终止符的文本文件是一个常见错误。

无论使用哪种方法,用户都可以简单地启动程序

java -jar MyProgram.jar

根据操作系统配置的不同,用户甚至可以通过双击JAR文件图标来启动应用程序。以下是各种操作系统的行为:

  • 在Windows上,Java运行时安装器创建一个文件关联到“.jar”扩展,它被关联到javaw -jar命令。(与java命令不同,javaw命令不打开shell窗口。)
  • 在Mac OS X上,操作系统识别“.jar”文件扩展名,并在双击JAR文件时执行Java程序。

然而,JAR文件中的Java程序与原生应用程序没有相同的感觉。在Windows上,可以使用第三方包装包装程序将JAR文件转换为Windows可执行文件。包装器是一个Windows程序,使用熟悉的.exe扩展来定位和启动Java虚拟机(JVM),或者告诉用户当没有找到JVM时该做什么。有许多商业和开源产品,如Launch4J(http://launch4j.sourceforge.net)和IzPack(http://izpack.org)。

4.8.4 多版本JAR文件

随着模块的引入和包的强封装,一些以前可访问的内部API不再可用。例如,JavaFX 8有一个内部类com.sun.javafx.css.CssParer。如果您使用它来分析样式表,那么您会发现您的程序不再编译。补救方法是简单切换到javafx.css.CssParser,这在Java 9中可用。但现在你有问题了。您需要为Java 8和Java 9用户分发不同的应用程序,或者需要使用类加载和反射来进行技巧操作。

为了解决这类问题,Java 9引入了多版本JAR,它们可以包含不同Java版本的类文件。

为了向后兼容,附加的类文件放在META-INF/versions目录中:

假设Application类使用了CssParser类。

然后传统的Application.class文件会使用com.sum.javafx.css.CssParser来编译,而Java 9版本使用javafx.css.CssParser来编译。

Java 8对META-INF/versions目录一无所知,只需加载遗留类即可。当JAVA 9读取JAR文件时,使用新版本来代替。

要添加版本化类文件,请使用–release标志:

jar uf MyProgram.jar --release 9 Application.class

要从头开始构建多版本JAR文件,请使用-C选项并为每个版本切换到不同的类文件目录:

jar cf MyProgram.jar -C bin/8 . --release 9 -C bin/9 Application.class

编译不同版本时,使用–release标志和-d标志指定输出目录:

javac -d bin/8 --release 8 . . .

至于Java 9,-d选项创建目录,如果它不存在。

在Java 9中,--release标志也是新的。在旧版本中,需要使用-source-target-bootclasspath标志。JDK现在附带了两个早期版本的API的符号文件。在Java 9中,可以用--release设置编译为9, 8或7。

多版本JAR不适用于程序或库的不同版本。对于这两个版本,所有类的公共API都应该相同。多版本JAR的唯一目的是使程序或库的特定版本能够与多个JDK版本一起工作。如果添加功能或更改API,则应改为提供JAR的新版本。

注意

诸如javap之类的工具没有被改装来处理多版本jar文件。如果你调用

javap -classpath MyProgram.jar Application.class

您得到了类的基本版本(毕竟,它应该具有与新版本相同的公共API)。如果您必须查看较新版本,请调用

javap -classpath MyProgram.jar\!/METAINF/versions/9/Application.class

4.8.5 关于命令行选项的说明

Java开发工具包中的命令选项传统上使用单破折号,然后使用多字母选项名称,例如

java -jar . . .
javac -Xlint:unchecked -classpath . . .

jar命令除外,它遵循tar命令的经典选项格式,不带破折号:

jar cvf ...

从Java 9开始,Java工具正在走向一种更常见的选项格式,其中多字母选项名称前面有双破折号,普通选项具有单字母快捷方式。例如,Linux ls命令可以用“human-readable”选项调用,如下所示

ls --human-readable

或者

ls -h

至于Java 9,可以使用--version而不是-version,以及--class-path路径而不是-classpath路径。正如您将在第二卷第9章中看到的,--module-path选项有一个快捷方式-p

您可以在http://openjdk.java.net/jeps/293上找到JEP 293增强请求的详细信息。作为清理的一部分,作者还建议标准化选项参数。带有--和多个字母的选项的参数由空格或=符号分隔:

javac --class-path /home/user/classdir . . .

或者

javac --class-path=/home/user/classdir . . .

单字母选项的参数可以用空格分隔,也可以直接跟在选项后面:

javac -p moduledir . . .

或者

javac -pmoduledir . . .

小心

后者目前不起作用,而且总的来说似乎是个坏主意。如果模块目录恰好是参数或处理器,如果模块目录恰好是arameters或者rocessor时,为什么要和传统选项冲突呢?

不带参数的单个字母选项可以组合在一起:

jar -cvf MyProgram.jar -e mypackage.MyProgram */*.class

小心

这目前还不起作用,而且肯定会导致混乱。假设javac有-c选项。那么javac -cp是指javac -c -p,还是传统的-cp

这造成了一个混乱,希望随着时间的推移将得到清理。尽管我们希望远离古老的jar选项,但最好还是等到尘埃落定。但是,如果您想完全现代化,可以安全地使用jar命令的长选项:

jar --create --verbose --file jarFileName file1 file2 . . .

如果不分组,单字母选项也有效:

jar -c -v -f jarFileName file1 file2 . . .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值