??xml version="1.0" encoding="utf-8" standalone="yes"?>
下面来看看什么是 JAR 文g包吧Q?
1. JAR 文g?
JAR 文g是 Java Archive FileQ顾名思意Q它的应用是?Java息息相关的,?Java的一U文档格式。JAR 文g非常cM ZIP 文g——准的_它就?ZIP 文gQ所以叫它文件包。JAR 文g?ZIP 文g唯一的区别就是在 JAR 文g的内容中Q包含了一?META-INF/MANIFEST.MF 文gQ这个文件是在生?JAR 文g的时候自动创建的。D个例子,如果我们h如下目录l构的一些文Ӟ
==
|-- test
| `-- Test.class
把它压羃?ZIP 文g test.zipQ则q个 ZIP 文g的内部目录结构ؓQ?
test.zip
|-- test
| `-- Test.class
如果我们使用 JDK ?jar 命o把它打成 JAR 文g?test.jarQ则q个 JAR 文g的内部目录结构ؓQ?
test.jar
|-- META-INF
| `-- MANIFEST.MF
|-- test
| `-- Test.class
2、创建可执行?JAR 文g?
制作一个可执行?JAR 文g包来发布你的E序?JAR 文g包最典型的用法?
Java E序是由若干?.class 文gl成的。这?.class 文g必须Ҏ(gu)它们所属的包不同而分U分目录存放Q运行前需要把所有用到的包的根目录指定给 CLASSPATH 环境变量或?java 命o?-cp 参数Q运行时q要到控制台下去使用 java 命o来运行,如果需要直接双击运行必d Windows 的批处理文g (.bat) 或?Linux ?Shell E序。因此,许多QJava 是一U方便开发者苦了用LE序设计语言?
其实不然Q如果开发者能够制作一个可执行?JAR 文g包交l用P那么用户使用h方便了。在 Windows 下安?JRE (Java Runtime Environment) 的时候,安装文g会将 .jar 文g映射l?javaw.exe 打开。那么,对于一个可执行?JAR 文g包,用户只需要双d?yu)可以运行程序了Q和阅读 .chm 文档一h?(.chm 文档默认是由 hh.exe 打开?。那么,现在的关键,是如何来创个可执行?JAR 文g包?
创徏可执行的 JAR 文g包,需要用带 cvfm 参数?jar 命oQ同样以上述 test 目录ZQ命令如下:
jar cvfm test.jar manifest.mf test
q里 test.jar ?manifest.mf 两个文gQ分别是对应的参?f ?mQ其重头戏在 manifest.mf。因创徏可执行的 JAR 文g包,光靠指定一?manifest.mf 文g是不够的Q因?MANIFEST ?JAR 文g包的特征Q可执行?JAR 文g包和不可执行?JAR 文g包都包含 MANIFEST。关键在于可执行 JAR 文g包的 MANIFESTQ其内容包含?Main-Class 一V这?MANIFEST 中书写格式如下:
Main-Class: 可执行主cd?包含包名)
例如Q假设上例中?Test.class 是属?test 包的Q而且是可执行的类 (定义?public static void main(String[]) Ҏ(gu))Q那么这?manifest.mf 可以~辑如下Q?
Main-Class: test.Test <回R>;
q个 manifest.mf 可以攑֜M位置Q也可以是其它的文g名,只需要有 Main-Class: test.Test 一行,且该行以一个回车符l束卛_。创Z manifest.mf 文g之后Q我们的目录l构变ؓQ?
==
|-- test
| `-- Test.class
`-- manifest.mf
q时候,需要到 test 目录的上U目录中M?jar 命o来创?JAR 文g包。也是在目录树中?#8220;==”表示的那个目录中Q用如下命令:
jar cvfm test.jar manifest.mf test
之后?#8220;==”目录中创Z test.jarQ这?test.jar 是执行?JAR 文g包。运行时只需要?java -jar test.jar 命o卛_?
需要注意的是,创徏?JAR 文g包中需要包含完整的、与 Java E序的包l构对应的目录结构,像上例一栗?Main-Class 指定的类Q也必须是完整的、包含包路径的类名,如上例的 test.TestQ而且在没有打?JAR 文g包之前可以?java <cd>; 来运行这个类Q即在上例中 java test.Test 是可以正运行的 (当然要在 CLASSPATH 正确的情况下)?
(注意事项及一些代码:)
手工写manifest.mf文g(jar命o自动生成的MANIFEST.MF文g中不会包含Main-Class属?QD例说明:
目录l构Q?/span>
mymanifest.mf //该文件可以随意放|?只要在执行jar命o时指定mymanifest.mf文g所在位|?
-src
-test
Test.class
test.Test代码Q?/span>
mymanifest.mf文g内容Q?/span>
Manifest-Version: 1.0
//该属性是创徏可执行jar包必需的,指定的Main-Class为全路径cdQ且该类必需有mainҎ(gu)Q?/span>
Main-Class: test.Test
Created-By: polaris
在src目录下执行:
jar cvfm test.jar ../mymanifest.mf .
完成后会在src目录下生成一个test.jar文g。由于没有可视化界面Q双击test.jar会看到没反应?/span>
在命令行执行java -jar test.jar׃得到输出HelloWorld!
q时完成了基本的创建可执行的jar包?/span>
创徏要依赖其他包的可执行jar包?/span>
q时只要更改mymanifest.mf文g加入Q?/span>
Manifest-Version: 1.0
//该属性是创徏可执行jar包必需的,指定的Main-Class为全路径cdQ且该类必需有mainҎ(gu)Q?/span>
Main-Class: test.Test
//该属性指定依赖包的\?路径是相对jar包所在\?
Class-Path: lib/swing-layout-1.0.jar //q里举例说明Q随便用的包
Created-By: KuKei
目录l构Q?/span>
-src
-test
TestDepends.class //假设该类执行依赖?swing-layout-1.0.jarQ具体代码略?/span>
testDepends.jar
-lib
swing-layout-1.0.jar
双击testDepends.jarp正确执行Q如果TestDepends.jar包所在的当前目录下没有lib/swing-layout-1.0.jar的话Q如下目录结构:
-src
-test
TestDepends.class //假设该类执行依赖?swing-layout-1.0.jarQ具体代码略?/span>
testDepends.jar
双击testDepends.jar,会报Could not find the main class, Program will exit.
在命令行执行 java -jar testDepends.jar,׃得到找不到TestDepends.class中所依赖的类的错?
3、用的Eclipse的导出功能制作可执行jar?/span>
在项目的Src上右键点击ExportQ选择导出目录Q重要的在第三步旉择自己写的mymanifest.mf文gQ?/span>
之所以jar包能执行是因ؓq个文g里面指定?em>Main-Class?/em>
4、jar 命o详解
jar 是随 JDK 安装的,?JDK 安装目录下的 bin 目录中,Windows 下文件名?jar.exeQLinux 下文件名?jar。它的运行需要用?JDK 安装目录?lib 目录中的 tools.jar 文g。不q我们除了安?JDK 什么也不需要做Q因?SUN 已经帮我们做好了。我们甚至不需要将 tools.jar 攑ֈ CLASSPATH 中?
使用不带M?jar 命o我们可以看到 jar 命o的用法如下:
jar {ctxu}[vfm0M] [jar-文g] [manifest-文g] [-C 目录] 文g?...
其中 {ctxu} ?jar 命o的子命oQ每?jar 命o只能包含 ctxu 中的一个,它们分别表示Q?
-c 创徏新的 JAR 文g?
-t 列出 JAR 文g包的内容列表
-x 展开 JAR 文g包的指定文g或者所有文?
-u 更新已存在的 JAR 文g?(d文g?JAR 文g包中)
[vfm0M] 中的选项可以任选,也可以不选,它们?jar 命o的选项参数
-v 生成详细报告q打印到标准输出
-f 指定 JAR 文g名,通常q个参数是必ȝ
-m 指定需要包含的 MANIFEST 清单文g
-0 只存储,不压~,q样产生?JAR 文g包会比不用该参数产生的体U大Q但速度更快
-M 不生所有项的清单(MANIFEST〕文Ӟ此参C忽略 -m 参数
[jar-文g] 即需要生成、查看、更新或者解开?JAR 文g包,它是 -f 参数的附属参?
[manifest-文g] ?MANIFEST 清单文gQ它?-m 参数的附属参?
[-C 目录] 表示转到指定目录下去执行q个 jar 命o的操作。它相当于先使用 cd 命o转该目录下再执行不带 -C 参数?jar 命oQ它只能在创建和更新 JAR 文g包的时候可用?
文g?... 指定一个文?目录列表Q这些文?目录是要添加到 JAR 文g包中的文?目录。如果指定了目录Q那?jar 命o打包的时候会自动把该目录中的所有文件和子目录打入包中?
下面举一些例子来说明 jar 命o的用法:
1) jar cf test.jar test
该命令没有执行过E的昄Q执行结果是在当前目录生成了 test.jar 文g。如果当前目录已l存?test.jarQ那么该文g被覆盖?
2) jar cvf test.jar test
该命令与上例中的l果相同Q但是由?v 参数的作用,昄Z打包q程Q如下:
标明清单(manifest)
增加Qtest/(d= 0) (写出= 0)(存储?0%)
增加Qtest/Test.class(d= 7) (写出= 6)(压羃?14%)
3) jar cvfM test.jar test
该命令与 2) l果cMQ但在生成的 test.jar 中没有包?META-INF/MANIFEST 文gQ打包过E的信息也略有差别:
增加Qtest/(d= 0) (写出= 0)(存储?0%)
增加Qtest/Test.class(d= 7) (写出= 6)(压羃?14%)
4) jar cvfm test.jar manifest.mf test
q行l果?2) 怼Q显CZ息也相同Q只是生?JAR 包中?META-INF/MANIFEST 内容不同Q是包含?manifest.mf 的内?
5) jar tf test.jar
?test.jar 已经存在的情况下Q可以查?test.jar 中的内容Q如对于 2) ?3) 生成?test.jar 分别应该此命令,l果如下Q?
对于 2)
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class
对于 3)
test/
test/Test.class
6) jar tvf test.jar
除显C?5) 中显C的内容外,q包括包内文件的详细信息Q如Q?
0 Wed Jun 19 15:39:06 GMT 2002 META-INF/
86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF
0 Wed Jun 19 15:33:04 GMT 2002 test/
7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class
7) jar xf test.jar
解开 test.jar 到当前目录,不显CZQ何信息,对于 2) 生成?test.jarQ解开后的目录l构如下Q?
==
|-- META-INF
| `-- MANIFEST
`-- test
`--Test.class
8) jar xvf test.jar
q行l果?7) 相同Q对于解压过E有详细信息昄Q如Q?
创徏QMETA-INF/
展开QMETA-INF/MANIFEST.MF
创徏Qtest/
展开Qtest/Test.class
9) jar uf test.jar manifest.mf
?test.jar 中添加了文g manifest.mfQ此使用 jar tf 来查?test.jar 可以发现 test.jar 中比原来多了一?manifest。这里顺便提一下,如果使用 -m 参数q指?manifest.mf 文gQ那?manifest.mf 是作为清单文?MANIFEST 来用的Q它的内容会被添加到 MANIFEST 中;但是Q如果作Z般文件添加到 JAR 文g包中Q它跟一般文件无异?
10) jar uvf test.jar manifest.mf
?9) l果相同Q同时有详细信息昄Q如Q?
增加Qmanifest.mf(d= 17) (写出= 19)(压羃?-11%)
5、关?JAR 文g包的一些技?/span>
1) 使用 unzip 来解?JAR 文g
在介l?JAR 文g的时候就已经说过了,JAR 文g实际上就?ZIP 文gQ所以可以用常见的一些解?ZIP 文g的工h解压 JAR 文gQ如 Windows 下的 WinZip、WinRAR {和 Linux 下的 unzip {。?WinZip ?WinRAR {来解压是因为它们解压比较直观,方便。而?unzipQ则是因为它解压时可以?-d 参数指定目标目录?
在解压一?JAR 文g的时候是不能使用 jar ?-C 参数来指定解压的目标的,因ؓ -C 参数只在创徏或者更新包的时候可用。那么需要将文g解压到某个指定目录下的时候就需要先这?JAR 文g拯到目标目录下Q再q行解压Q比较麻烦。如果?unzipQ就不需要这么麻烦了Q只需要指定一?-d 参数卛_。如Q?
unzip test.jar -d dest/
2) 使用 WinZip 或?WinRAR {工具创?JAR 文g
上面提到 JAR 文g是包含?META-INF/MANIFEST ?ZIP 文gQ所以,只需要?WinZip、WinRAR {工具创建所需?ZIP 压羃包,再往q个 ZIP 压羃包中d一个包?MANIFEST 文g?META-INF 目录卛_。对于?jar 命o?-m 参数指定清单文g的情况,只需要将q个 MANIFEST 按需要修改即可?
3) 使用 jar 命o创徏 ZIP 文g
有些 Linux 下提供了 unzip 命oQ但没有 zip 命oQ所以需要可以对 ZIP 文gq行解压Q即不能创徏 ZIP 文g。如要创Z?ZIP 文gQ用带 -M 参数?jar 命o卛_Q因?-M 参数表示制作 JAR 包的时候不d MANIFEST 清单Q那么只需要在指定目标 JAR 文g的地方将 .jar 扩展名改?.zip 扩展名,创徏的就是一个不折不扣的 ZIP 文g了,如将上一节的W?3) 个例子略作改动:
jar cvfM test.zip test
单来_Java的序列化机制是通过在运行时判断cȝserialVersionUID来验证版本一致性的。在q行反序列化ӞJVM会把传来的字节流中的serialVersionUID与本地相应实体(c)的serialVersionUIDq行比较Q如果相同就认ؓ是一致的Q可以进行反序列化,否则׃出现序列化版本不一致的异常?br />
当实现java.io.Serializable接口的实体(c)没有昑ּ地定义一个名为serialVersionUIDQ类型ؓlong的变量时QJava序列化机制会Ҏ(gu)~译的class自动生成一个serialVersionUID作序列化版本比较用,q种情况下,只有同一ơ编译生成的 class才会生成相同的serialVersionUID ?br />
如果我们不希望通过~译来强制划分Y件版本,卛_现序列化接口的实体能够兼容先前版本,未作更改的类Q就需要显式地定义一个名为serialVersionUIDQ类型ؓlong的变量,不修改这个变量值的序列化实体都可以怺q行串行化和反串行化?br />