jar 包
# jar 包
jar 包:Java 类的压缩包
# 引出 jar 包的概念
如果我们想让同事使用我们的编写的类,可以怎么做呢?
比如,我们写了一个工具类,可以通过发送单个文件的方式,给到同事;
但如果我们写了多个类呢?并且每个类是按包存储的,一个个文件发给同事,太麻烦了,我们可以打个压缩包给到同事,同事拿到后再解压到对应的目录…………
在一个大型项目中,这样就有点不可取了。因为我们一个项目可能有很多很多的工具类,可能多达几十个,传统的文件管理太麻烦了:
- 需要记住每个工具类的路径,然后 import;
- 依赖于具体操作系统的文件系统。当需要迁移到其他操作系统的时候,需要重新压缩包和传输;
- 更新问题:当工具类有更新,就需要重新解压到特定的文件夹。。。。
因此,Java 提供了一种文件格式,可以将工具类压缩后,不解压也能使用里面的类(包括 import 和使用里面的方法),这种文件格式就 jar 包,是一种以 .jar
后缀结尾的文件。
我们可以进入 C:\Program Files\Java\jdk1.8.0_281\jre\lib (笔者安装到了 C 盘,请读者自行更换自己的 Java 安装目录),可以看到有不少 jar 包:
C:\Program Files\Java\jdk1.8.0_281\jre\lib
我们复制一份其中的 rt.jar 包到其他目录,并修改文件后缀名为 .zip,然后打开:
可以看到里面有很多的 class 类,这些就是 Java 提供给我们使用的类。
我们也可以自己生成一个 jar 包,提供给其他人使用,好处如下:
- 这样别人只需用我们的 jar 包,不用解压,
- 当需要迁移到其他操作系统的时候直接挪到 jar 包即可;
- 当版本有更新的时候只需更换 jar 包;
- 各个工具类直接是独立的 jar 包,不会互相混杂
- …………
# 生成一个 jar 包
按照 Java 的规范,一般类都是用包来组织的。我们按域名的结构新建目录,并定义一个类:
D:\>md com\peterjxl //Windows下
mkdir com/peterjxl //Linux下
2
package com.peterjxl;
public class Hello{
public static void main(String[] args) {
System.out.println("Hello Jar");
}
}
2
3
4
5
6
7
然后编译生成 class 文件,因为我们最后是用到 class 文件的
D:\> javac com/peterjxl/Hello.java
因为 jar 包就是 zip 包,所以,直接在资源管理器中,找到正确的目录,点击右键,在弹出的快捷菜单中选择“发送到”,“压缩(zipped)文件夹”,就制作了一个 zip 文件。然后,把后缀从 .zip
改为 .jar
,一个 jar 包就创建成功。
我们这里重命名为 MyJar.jar
# 使用一个 jar 包
我们要引用 jar 包里的类,只需在编译和运行的时候,指定 classpath 即可
我们在 D 盘新建一个 Main.java,里面引入 Hello 类。
import com.peterjxl.Hello;
public class Main{
public static void main(String[] args) {
Hello o = new Hello();
o.main(null);
}
}
2
3
4
5
6
7
8
我们编译和运行:(注意,运行和编译前先删除之前我们新建的 java 文件)
D:\> javac -cp Myjar.jar Main.java
D:\> java -cp "Myjar.jar;." Main
Hello Jar
2
3
如果要使用多个 jar 包, 则 jar 包之间用分号 ; 分割,例如:
C:\dependency\framework.jar;C:\location\otherFramework.jar
# 运行一个 jar 包
jar 包还可以包含一个特殊的 /META-INF/MANIFEST.MF
文件,MANIFEST.MF
是纯文本,可以指定 Main-Class
和其它信息。JVM 会自动读取这个 MANIFEST.MF
文件,如果存在 Main-Class
,我们就不必在命令行指定启动的类名,而是用更方便的命令:
java -jar hello.jar
我们来尝试下。我们先解压之前的 jar 包,在里面新建一个 /META-INF/MANIFEST.MF
文件,里面存放的内容如下:
Main-Class: com.peterjxl.Hello
2
注意:
- Main-Class: 后面要空一格,再写上完整类名。
- 最下面一行是一行空行,不然会报错
MyJar.jar中没有主清单属性
。如果没有 Main-Class 也会报这个错 - 更多信息,可以参考官方文档:Working with Manifest Files: The Basics (The Java™ Tutorials > Deployment > Packaging Programs in JAR Files) (opens new window)
若要指定运行类名,则用:
java -cp path classname
# 其他方式创建 jar 包
除了自己手工生成压缩包之外,Java 还提供了命令行给我们调用,使得我们可以在命令行里创建 jar 包。
jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files .
..
选项:
-c 创建新档案
-t 列出档案目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有档案
-v 在标准输出中生成详细输出
-f 指定档案文件名
-m 包含指定清单文件中的清单信息
-n 创建新档案后执行 Pack200 规范化
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含以下文件
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序
与 'm', 'f' 和 'e' 标记的指定顺序相同。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
表 1. 常见的 jar 工具用法
功能 | 命令格式 | 举例 |
---|---|---|
用一个单独的文件创建一个 JAR 文件 | jar cf jar-file file-name | |
用一个单独的文件创建一个 JAR 文件,并显示压缩过程 | jar cvf test.jar test | |
用一个目录创建一个 JAR 文件 | jar cf jar-file dir-name | jar cf Myjar.jar com |
创建一个未压缩的 JAR 文件 | jar cf0 jar-file dir-name | |
更新一个 JAR 文件 | jar uf jar-file input-file... | |
查看一个 JAR 文件的内容 | jar tf jar-file | |
提取一个 JAR 文件的内容 | jar xf jar-file | |
从一个 JAR 文件中提取特定的文件 | jar xf jar-file archived-file... | |
运行一个打包为可执行 JAR 文件的应用程序 | java -jar app.jar |
我们试着创建一个 jar 包,并用-e 选项指定程序入口的主类名(记得先删除之前的我们手工压缩改后缀名的 jar 包)
D:\> jar cvfe Myjar.jar com.peterjxl.Hello com
已添加清单
正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/peterjxl/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/peterjxl/Hello.class(输入 = 426) (输出 = 293)(压缩了 31%)
正在添加: com/peterjxl/Hello.java(输入 = 130) (输出 = 118)(压缩了 9%)
2
3
4
5
6
用压缩文件打开 jar 包,可以看到里面默认有 MANIFEST.MF
文件,不用我们自己生成了,方便了很多。
我们试着运行:
D:\> java -jar Myjar.jar
Hello Jar
2
其他命令不一一试了,读者了解即可。
一般情况下,IDE 也提供了创建 jar 包的方法,不同 IDE 的操作方法不同,这里不详细展开了。
# 多个 jar 包
如果 jar 包很多个,一个个指定的话非常麻烦。此时可以用通配符星号:*.jar
或者将 jar 包移动一个目录里,然后运行程序的时候指定目录(这里假设放到 lib 牡蛎里):
java -Djava.ext.dirs=lib Main
注意,该方法得 Java1.6 以上才可以
# 小结
使用 jar 包的好处,专业一点的说法如下:
- 安全,可以对其进行数字签名,只让能够识别数字签名的用户使用里面的东西。
- 加快下载速度;
- 压缩,使文件变小,与 ZIP 压缩机制完全相同。
- 包封装。能够让 JAR 包里面的文件依赖于统一版本的类文件。
- 可移植性,能够在各种平台上直接使用。
- 把一个 JAR 文件添加到系统的 classpath 环境变量之后,java 通常会把这个 JAR 文件当做一个路径来处理。通常使用 jar 命令来压缩,可以把一个或多个路径全部压缩成一个 JAR 文件。
在 IDE 中运行 Java 程序,IDE 自动传入的 -cp
参数是当前工程的 bin
目录和引入的 jar 包,无需使用这么复杂的命令。