corejava11(4.8 JAR文件)

本文围绕Java JAR文件展开,介绍了其用途,可包含类文件、图像等并采用zip压缩。详细阐述了创建JAR文件的方法、清单文件的作用及编辑方式,还说明了可执行JAR文件的启动方法、多版本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 . . .
C:\Users\33512\.jdks\corretto-17.0.12\bin\java.exe -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2023.2.1\lib\idea_rt.jar=56111:C:\Program Files\JetBrains\IntelliJ IDEA 2023.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\idea\FileManageSystem\file-system\target\classes;D:\MAVEN\repo\com\alibaba\cloud\spring-cloud-starter-alibaba-seata\2.2.8.RELEASE\spring-cloud-starter-alibaba-seata-2.2.8.RELEASE.jar;D:\MAVEN\repo\org\springframework\boot\spring-boot-starter-aop\2.3.12.RELEASE\spring-boot-starter-aop-2.3.12.RELEASE.jar;D:\MAVEN\repo\org\springframework\spring-aop\5.2.15.RELEASE\spring-aop-5.2.15.RELEASE.jar;D:\MAVEN\repo\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\MAVEN\repo\io\seata\seata-spring-boot-starter\1.5.1\seata-spring-boot-starter-1.5.1.jar;D:\MAVEN\repo\io\seata\seata-spring-autoconfigure-client\1.5.1\seata-spring-autoconfigure-client-1.5.1.jar;D:\MAVEN\repo\io\seata\seata-spring-autoconfigure-core\1.5.1\seata-spring-autoconfigure-core-1.5.1.jar;D:\MAVEN\repo\io\seata\seata-all\1.5.1\seata-all-1.5.1.jar;D:\MAVEN\repo\io\netty\netty-all\4.1.65.Final\netty-all-4.1.65.Final.jar;D:\MAVEN\repo\org\antlr\antlr4\4.8\antlr4-4.8.jar;D:\MAVEN\repo\org\antlr\antlr4-runtime\4.8\antlr4-runtime-4.8.jar;D:\MAVEN\repo\org\antlr\antlr-runtime\3.5.2\antlr-runtime-3.5.2.jar;D:\MAVEN\repo\org\antlr\ST4\4.3\ST4-4.3.jar;D:\MAVEN\repo\org\abego\treelayout\org.abego.treelayout.core\1.0.3\org.abego.treelayout.core-1.0.3.jar;D:\MAVEN\repo\org\glassfish\javax.json\1.0.4\javax.json-1.0.4.jar;D:\MAVEN\repo\com\ibm\icu\icu4j\61.1\icu4j-61.1.jar;D:\MAVEN\repo\com\alibaba\druid\1.2.6\druid-1.2.6.jar;D:\MAVEN\repo\com\typesafe\config\1.2.1\config-1.2.1.jar;D:\MAVEN\repo\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\MAVEN\rep
最新发布
03-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值