前一阵子需要把一个原本在 Windows 环境下的 Java Eclipse 项目放到 Linux 环境下测试,由于不想在 Linux 虚拟机中装 Eclipse,于是索性打算用命令来运行测试该项目。结果花了半小时,终于把项目跑起来了。

java打包的扩展名 javac 打包_Java

java打包的扩展名 javac 打包_Java

java打包的扩展名 javac 打包_Java

事后实验总结了一下,于是有了这篇博文。

带 package 包名 Java 进程的编译和运行

首先我们来新建一个测试类 HelloJava。

package com.thomastian.test;
public class HelloJava
{
public static void main(String args[])
{
System.out.println("Hello, Java");
}
}

直接编译(不推荐)$ javac HelloJava.java

带目录结构的编译$ javac -d . HelloJava.java

java打包的扩展名 javac 打包_Java_04

加上了 -d 选项后在当前目录下建立了对应包层次的目录结构(如上图)。如果没有加 -d,则在当前目录下生成 class 文档,需手动建立目录结构。

在运行时,需要加上主类对应的目录层次,可以采用包形式“.”,或者目录的形式“/”,这样 JVM 就会根据目录层次来查找对应的 class 文档并执行。执行目录必须是包顶级层次的上级目录(在这里就是 com 的上级目录“~”了)。$ java com.thomastian.test.HelloJava

$ java com/thomastian/test/HelloJava

Java的归档(jar)

Java 使用 jar 命令打包(创建归档文档)。(jar 命令的选项跟 tar 命令是相同的,毕竟都是打包归档类的命令。)

这里前面的“HelloJava.jar”对应包的名称,后面的“com”对应的包的根目录。$ jar cvf HelloJava.jar com

运行 jar:$ java -jar HelloJava.jar

此时会提示错误:

java打包的扩展名 javac 打包_java 打包jar 命令_05

用解压软件打开 jar 包文档,可以看到里面有一个 MAINFEST.MF 文档。

java打包的扩展名 javac 打包_java 打包jar 命令_06

Manifest-Version: 1.0

Created-By: 1.8.0_65 (Oracle Corporation)

这是一个在归档时自动生成的文档,它是 JAR 档案文档中的特殊文档,用来定义扩展或档案打包相关数据。

如果 JAR 文档被用作可执行的应用进程,那么应用进程需要告诉 Java 虚拟机入口点位置,任意包含 public static void main(String[] args) 方法的类即为入口点。该信息由文档头 Main-Class 提供,基本格式如下:

Main-Class: classname

以上内容摘自维基百科条目:Manifest 资源配置文档,详细讲解了 Manifest 文档的用法以及相关资料。

接下来我们创建一个文本文档 Mainfest(随便什么名字都行),在文档中添加 Main-Class 值,注意冒号后面有空格,不然会报错,然后保存。

Manifest-Version: 1.0

Created-By: 1.8.0_65 (Oracle Corporation)

Main-Class: com.thomastian.test.HelloJava

在 jar 命令加上 f 选项,即可指定自定义的 Mainfest 文档,在包名的后面加上刚才创建的文档名“mainfest”。在运行完命令时,mainfest 文档的内容就会赋给 jar 包中的 MAINFEST.MF 文档,完成了 MAINFEST 文档的自定义。$ jar cvfm HelloJava.jar mainfest com

java打包的扩展名 javac 打包_jar_07

生成 jar 包后,再执行 java -jar HelloJava.jar 命令即可成功运行。在设定了 jar 的文档关联后甚至可以双击运行,十分方便。

上面说过,被用作可执行的应用进程的 jar 包才需要指定 Main-Class,有些包是供其它进程调用的类库,并没有 main 方法,下文的 ImportClass 类就是这样。

jar包的引用

上文讲的是如何创建 jar 包,接下来我们来看看包的引用。

首先我们创建一个 ImportClass 类,用于引用。注意待引用的类必须为 public 类型,否则对外是不可见的,这样也就无法引用了。

package blog.thomastian.test;
public class ImportClass{
public void print()
{
System.out.println("oh, my import class!");
}
}

按照上文的方法将其编译为 jar 包。由于该文档没有 main 方法,所以也就无需指定 Main-Class 了。

修改前面的 HelloJava 类,引用并调用上面的 ImportClass 类。

package com.thomastian.test;
import blog.thomastian.test.ImportClass;
public class HelloJava
{
public static void main(String args[])
{
ImportClass ic = new ImportClass();
ic.print();
}
}

编译:$ javac -d . -cp lib/ImportClass.jar HelloJava.java

运行:$ java -cp .:lib/ImportClass.jar com.thomastian.test.HelloJava

java打包的扩展名 javac 打包_java_08

多个路径之间用“:”(Linux) / “;”(Windows)隔开(跟系统环境变量的写法相同)。在编译的时候 -cp 路径可以不包含当前路劲,但是在运行的时候必须要加上代表当前路径的“.”,具体可参考这篇stackoverflow问答。