Jar 文件(学习 Java 编程语言 037)

Java 归档(JAR)文件设计的目的:
在应用程序打包时,希望只向用户提供一个单独的文件,而不是一个包含大量类文件的目录结构。

JAR 文件既可以包含类文件,也可以包含诸如图像和声音等其他类型的文件。JAR 文件是压缩的,JAR 文件使用了我们熟悉的 ZIP 压缩格式。可以使用任何 ZIP 工具查看 JAR 文件。

提示: pack200 是一种较通常的 ZIP 压缩算法更加有效的压缩类文件的方式。Oracle 声称,对类文件的压缩率接近 90%。

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 ...

可以将应用程序和代码库打包在 JAR 文件中。

java 程序选项

选项说明
c创建一个新的或者空的存档文件并加人文件。如果指定的文件名是目录,jar 程序将会对它们进行递归处理
C暂时改变目录,例如: jar cvf jarFileName.jar -C classes *.class 改变到 classes 子目录以便增加类文件
e在清单文件中创建一个入口点
f指定 JAR 文件名作为第二个命令行参数。如果没有这个参数,jar 命令会将结果写至标准输出(在创建 JAR 文件时)或者从标准输入读取(在解压或者列出 JAR 文件内容时)
i建立索引文件(用于加快大型归档的查找)
m将一个清单文件(manifest)添加到 JAR 文件中。清单是对归档内容和来源的一个说明。每个归档有一个默认的清单文件。但是,如果想验证归档文件的内容,可以提供自己的清单文件
M不为条目创建清单文件
t显示内容表
u更新一个已有的 JAR 文件
v生成详细的输出结果
x解压文件。如果提供一个或多个文件名,只解压这些文件;否则,解压所有文件
0存储,不进行 ZIP 压缩

2. 清单文件

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

清单文件被命名为 MANIFEST.MF,它位于 JAR 文件的一个特殊 META-INF 子目录中。符合标准的最小清单文件极其简单:
Manifest-Version: 1.0

复杂的清单文件可能包含更多条目。这些清单条目被分成多个节。第一节被称为主节(main section)。它作用于整个 JAR 文件。随后的条目用来指定命名实体的属性,如单个文件、包或者 URL。它们都必须以一个 Name 条目开始。节与节之间用空行分开。例如:

Mainfest-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.html 获得有关 JAR 文件和清单文件格式的更多信息。

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 和 IzPack。

4. 打包 Jar 包示例

ResourceTest.mf 内容:

Main-Class: com.xiang117.corejava.ResourceTest

目录结构:

ResourceTest.mf
com
  └─xiang117
      └─corejava
          ├──about.png
          ├──ResourceTest.class
          └──data
                ├──content.txt
                └──title.txt

打包命令:
jar cvfm ResourceTest.jar ResourceTest.mf com/xiang117/corejava/*.class com/xiang117/corejava/*.png com/xiang117/corejava/data/*.txt
java -jar ResourceTest.jar

5. 多版本 JAR 文件

随着模块和包强封装的引入,之前可以访问的一些内部 API 不再可用。例如,JavaFX 8 有一个内部类 com.sun.javafx.css.CssParser。如果用它解析一个样式表,你会发现你的程序不再能正常编译了。补救很简单,只需要改用 Java 9 提供的 javafx.css.CssParser。不过这样会有一个问题。你需要向 Java 8 和 Java 9 用户发布不同的应用程序,或者需要利用类加载器和反射等一些技巧。

为了解决类似这样的问题,Java 9 引入了多版本 JAR(multi-release JAR),其中可以包含面向不同 Java 版本的类文件。
为了保证向后兼容,额外的类文件放在 META-INF/version 目录中:

Application.class
BuildingBlocks.class
Util.class
META-INF
  ├──MANIFEST.MF(with line Multi-Release: true)
  ├──versions
  ├──9
  │  ├──Application.class
  │  └──BuildingBlocks.class
  └──10
     └──BuildingBlocks.class

假设 Application 类使用了 CssParse 类。那么遗留版本的 Application.class 文件可以使用 com.sun.javafx.css.CssParser,而 Java 9 版本可以使用 javafx.css.CssParser

Java 8 完全不知道 META-INF/version 目录,它只会加载遗留的类。Java 9 读取这个 JAR 文件时,则会使用新版本。

要增加不同版本的类文件,可以使用 --release 标志:
jar uf MyProgram.jar --release 9 Application.class

要从头构建一个多版本的 JAR 文件,可以使用 -C 选项,对应每个版本要切换到一个不同的类文件目录:
javac cf MyProgram.jar -C bin/8 . --release 9 -C bin/9 Application.class
面向不同版本编译时,要使用 --release 标志和 -d 标志来指定输出目录:
javac -d bin/8 --release 8 ...

在 Java 9 中,-d 选项会创建这个目录(如果原先的目录不存在)。
–release 标志也是 Java 9 新增的。在较早的版本中,需要使用 -source、-target 和 -boot-classpath 标志。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\!/META-INFO/version/9/appliaction.class

6. 关于命令行选项说明

Java 开发包(JDK)的命令行选项一直以来都使用单个短横线加多字母选项名的形式,如:
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。

详细内容可以参见 JEP 293 增强请求(http://openjdk.java.net/jeps/293)。在所有清理工作中,作者还提出要标准化选项参数。带 – 和多字母的选项的参数用空格或者一个等号(=)分割:
javac --class-path /home/user/classdir ...

javac --class=path=/home/user/classdir ...
单字母选项的参数可以用空格分割,或者直接跟在选项后面:
javac -p moduledir ...

javac -pmoduledir ...

警告: 后一种方式现在不能使用,而且一般来讲这也不是一个好主意。如果模块目录恰好是 arametes 或 rocessor,这就很容易与遗留的选项发生冲突。

无参数的单字母选项可以混合在一起:
jar -cvf MyProgram.jar -e mypackage.MyProgram */*.class

警告: 目前不能使用这种方式。这肯定会带来混淆。假设 javac 有一个 -c 选项。那么 javac -cp 是指 java -c -p 还是 -cp?

这就会带来一些混乱,希望过段时间能够解决这个问题。尽管我们想要远离这些古老的 jar 选项,但最好还是等到尘埃落定为妙。不过,如果你想做到最现代化,那么可以安全地使用 jar 命令的长选项:
jar --create --verbose --file jarFileName file1 file2 ...
对于单字母选项,如果不组合,也是可以使用的:
jar -c -v -f jarFileName file1 file2 ...

7. 密封

Java 包密封(seal)可以保证不会有其他的类加入到其中。如果在代码中使用了包可见的类、方法和域,就可能希望密封包,如果不密封,其他类就有可能放在这个包中,进而访问包可见的特性。

如果密封了 com.mycompany.util 包,就不能用下面的语句顶替密封包之外的类:
package com.mycompany.util
要想密封一个包,需要将包中的所有类放到一个 JAR 文件中。在默认情况下,JAR 文件中的包是没有密封的。可以在清单文件的主节中加入下面一行:
Sealed: true
来改变全局的默认设定。对于每个单独的包,可以通过在 JAR 文件的清单中增加一节,来指定是否想要密封这个包。例如

Name: com/mycompany/util/
Sealed: true

Name: com/mycompany/misc/
Sealed: true

要想密封一个包,需要创建一个包含清单指令的文本文件。然后用常规的方式运行 jar 命令:
jar cvfm MyArchive.jar manifest.mf files to add

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值