java · 2019-08-31 0

命令行打jar包及使用

一、编写java文件

Test1.java

package com.test1;

public class Test1{
    public void display(){
        System.out.println("This is test1");
    }
}

Test2.java

package com.test2;

public class Test2{ 
    public void display(){
        System.out.println("This is Test2");
    }
}

Test.java

package com.test;

import com.test1.Test1;
import com.test2.Test2;

public class Test{
    public static void main(String[] args){
        for(String s : args){
            System.out.println("arg:"+s);
        }
        Test1 t1 = new Test1();
        t1.display();
        Test2 t2 = new Test2();
        t2.display();
    }
}

三个java文件放在 /home/zxm/testjar 下,再新建 foo1 目录,用于存放编译生成的 class 文件

目录结构:

foo1/
Test.java
Test1.java
Test2.java

二、编译文件

java版本:

zxm@zxm-pc:~/testjar$ java -version
java version "1.8.0_341"
Java(TM) SE Runtime Environment (build 1.8.0_341-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.341-b10, mixed mode)

java命令使用:

zxm@zxm-pc:~/testjar$ java -help
用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32      使用 32 位数据模型 (如果可用)
    -d64      使用 64 位数据模型 (如果可用)
    -server   选择 "server" VM
                  默认 VM 是 server,
                  因为您是在服务器类计算机上运行。

    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>
                  用 : 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<值>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<值>
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕

javac命令使用:

zxm@zxm-pc:~/testjar$ javac -help
用法: javac <options> <source files>
其中, 可能的选项包括:
  -g                         生成所有调试信息
  -g:none                    不生成任何调试信息
  -g:{lines,vars,source}     只生成某些调试信息
  -nowarn                    不生成任何警告
  -verbose                   输出有关编译器正在执行的操作的消息
  -deprecation               输出使用已过时的 API 的源位置
  -classpath <路径>            指定查找用户类文件和注释处理程序的位置
  -cp <路径>                   指定查找用户类文件和注释处理程序的位置
  -sourcepath <路径>           指定查找输入源文件的位置
  -bootclasspath <路径>        覆盖引导类文件的位置
  -extdirs <目录>              覆盖所安装扩展的位置
  -endorseddirs <目录>         覆盖签名的标准路径的位置
  -proc:{none,only}          控制是否执行注释处理和/或编译。
  -processor <class1>[,<class2>,<class3>...] 要运行的注释处理程序的名称; 绕过默认的搜索进程
  -processorpath <路径>        指定查找注释处理程序的位置
  -parameters                生成元数据以用于方法参数的反射
  -d <目录>                    指定放置生成的类文件的位置
  -s <目录>                    指定放置生成的源文件的位置
  -h <目录>                    指定放置生成的本机标头文件的位置
  -implicit:{none,class}     指定是否为隐式引用文件生成类文件
  -encoding <编码>             指定源文件使用的字符编码
  -source <发行版>              提供与指定发行版的源兼容性
  -target <发行版>              生成特定 VM 版本的类文件
  -profile <配置文件>            请确保使用的 API 在指定的配置文件中可用
  -version                   版本信息
  -help                      输出标准选项的提要
  -A关键字[=值]                  传递给注释处理程序的选项
  -X                         输出非标准选项的提要
  -J<标记>                     直接将 <标记> 传递给运行时系统
  -Werror                    出现警告时终止编译
  @<文件名>                     从文件读取选项和文件名

另:
可以向低版本编译,例,javac -d foo1/ Test1.java Test2.java Test.java -encoding UTF-8 -source 7 -target 7

编译的文件放在 foo1 目录下,使用 javac 命令编译,-d 指定 class 文件存放目录

使用 java 命令运行程序

zxm@zxm-pc:~/testjar$ mkdir foo1/
zxm@zxm-pc:~/testjar$ javac -d foo1/ Test1.java Test2.java Test.java
zxm@zxm-pc:~/testjar$ java -cp foo1/ com.test.Test
This is test1
This is Test2
zxm@zxm-pc:~/testjar/foo1$ java com.test.Test
This is test1
This is Test2

目录结构:

foo1
    com
        test
            Test.class
        test1
            Test1.class
        test2
            Test2.class
Test.java
Test1.java
Test2.java

三、编写清单文件(MANIFEST.MF)

/home/zxm/testjar 目录下,新建文件 MANIFEST.MF (可以自定义名,jar 会把清单文件里的内容放到,生成 jar 文件的 META-INF 目录下 MANIFEST.MF 文件中,用解压文件解压 jar 可以看到)。Manifest-Version 指定版本号;Main-Class 指定程序入口,实现直接执行jar文件

也可以不编写 MANIFEST.MF 文件,使用 jar 打包时候指定主类

MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.test.Test

注意:在每行冒号后有空格;文件最后一行为空行

四、打jar包

jar命令使用:

zxm@zxm-pc:~/testjar$ 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' 标记的指定顺序相同。

示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中:
       `jar cvf classes.jar Foo.class Bar.class`
示例 2: 使用现有的清单文件 'mymanifest' 并
           将 foo/ 目录中的所有文件归档到 'classes.jar' 中:
       `jar cvfm classes.jar mymanifest -C foo/ .`

1.指定主类:使用 jar cvfe 命令打包

2.指定清单文件:使用 jar cvfm 命令打包,t.jar 为打的包名;MANIFEST.MF 为清单文件;-C 更改为指定的目录并包含其中的文件,如果文件为目录,则递归处理;.表示当前路径

3.不指定清单文件:使用 jar cvf t.jar -C foo1/ . ,也能打包成功,但是自动生成的清单里没有指定 Main-Class

# zxm@zxm-pc:~/testjar$ jar cvfe t.jar com.test.Test -C foo1/ .
# 已添加清单
# 正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)
# 正在添加: com/test/(输入 = 0) (输出 = 0)(存储了 0%)
# 正在添加: com/test/Test.class(输入 = 786) (输出 = 503)(压缩了 36%)
# 正在添加: com/test2/(输入 = 0) (输出 = 0)(存储了 0%)
# 正在添加: com/test2/Test2.class(输入 = 405) (输出 = 285)(压缩了 29%)
# 正在添加: com/test1/(输入 = 0) (输出 = 0)(存储了 0%)
# 正在添加: com/test1/Test1.class(输入 = 405) (输出 = 285)(压缩了 29%)
zxm@zxm-pc:~/testjar$ jar cvfm t.jar MANIFEST.MF -C foo1/ .
已添加清单
正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/test/Test.class(输入 = 786) (输出 = 503)(压缩了 36%)
正在添加: com/test2/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/test2/Test2.class(输入 = 405) (输出 = 285)(压缩了 29%)
正在添加: com/test1/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/test1/Test1.class(输入 = 405) (输出 = 285)(压缩了 29%)

此时目录结构:

foo1
    com
        test
            Test.class
        test1
            Test1.class
        test2
            Test2.class
MANIFEST.MF
t.jar
Test.java
Test1.java
Test2.java

五、运行jar包

使用 java -jar <jar_name> 命令运行 jar

zxm@zxm-pc:~/testjar$ java -cp foo1/ com.test.Test
This is test1
This is Test2
zxm@zxm-pc:~/testjar/foo1$ java com.test.Test
This is test1
This is Test2
zxm@zxm-pc:~/testjar$ java -jar t.jar
This is test1
This is Test2
zxm@zxm-pc:~/testjar$ java -jar t.jar a b c
arg:a
arg:b
arg:c
This is test1
This is Test2

六、使用jar包

/home/zxm/testjar 下新建 MyMain.java 文件,MyMain.java 使用到 Test1

package main;

import com.test1.Test1;

public class MyMain{
    public static void main(String[] args){
        Test1 t1 = new Test1();
        t1.display();
    }
}

javac 编译 MyMain.java 文件。

-d . 指定编译的文件放在当前目录下,对于 MyMain.java 写了 package mainMyMain.javaclass 文件会放在当前文件 main/MyMain.class

-cp(-classpath) 指定 classpath ,如果不指定默认,classpath 是当前目录,MyMain.java 使用到 com.test1.Test1 类文件,编译 MyMain.java 时,编译器会找当前目录下 comtest1Test1.class,此时是找不到的,会提示程序包 com.test1 不存在编译失败,-cp 指定类加载器去 t.jar 里找 comtest1Test1.class

java 命令运行 MyMain

-cp 指定 classpathfoo1/,则可以找到 Test1.class 文件,或者指定 classpatht.jar,则从 jar 包中,找到 Test1.class 文件

zxm@zxm-pc:~/testjar$ mkdir foo2/
# zxm@zxm-pc:~/testjar$ javac -d foo2/ -cp foo1/ MyMain.java
zxm@zxm-pc:~/testjar$ javac -d foo2/ -cp t.jar MyMain.java
zxm@zxm-pc:~/testjar$ java -cp foo1/:foo2/ main.MyMain
This is test1
zxm@zxm-pc:~/testjar$ java -cp t.jar:foo2/ main.MyMain
This is test1

七、jar打jar包

/home/zxm/testjar 新建清单文件 my.mf(自定义名,jar会把清单文件里的内容放到,生成 jar 文件的 META-INF 目录下 MANIFEST.MF 文件中,用解压文件解压 jar 可以看到)

Class-Path指定包含的jar,如果包含多个,用空格隔开

Manifest-Version: 1.0
Class-Path: t.jar
Main-Class: main.MyMain

jar命令打包,直接执行java -jar jar包就可成功运行

zxm@zxm-pc:~/testjar$ jar cvfm main.jar my.mf -C foo2/ .
已添加清单
正在添加: main/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: main/MyMain.class(输入 = 328) (输出 = 250)(压缩了 23%)
zxm@zxm-pc:~/testjar$ java -jar main.jar 
This is test1

查看 jar 包内容

zxm@zxm-pc:~/testjar$ jar -tf main.jar 
META-INF/
META-INF/MANIFEST.MF
main/
main/MyMain.class

解压 jar 包

jar -xvf <jar_name> 解压到当前目录,使用 unzip 可解压到指定目录

# zxm@zxm-pc:~/testjar/t$ jar -xvf main.jar
zxm@zxm-pc:~/testjar/t$ unzip main.jar -d temp/
Archive:  main.jar
   creating: temp/META-INF/
  inflating: temp/META-INF/MANIFEST.MF
   creating: temp/main/
  inflating: temp/main/MyMain.class
zxm@zxm-pc:~/testjar$ cat temp/META-INF/MANIFEST.MF 
Manifest-Version: 1.0
Class-Path: t.jar
Created-By: 1.8.0_341 (Oracle Corporation)
Main-Class: main.MyMain