jar <--> tar
jar的Options中-c -t -x -u -f -v 几乎和tar的对应options如出一辙。需要额外记忆的有-0 -i -e -m -M -C,-m和-M 与MENIFEST.MF文件有关。
最基本的打包,jar cf pkg-name.jar ./pkg-folder or jar cf pkg-name.jar class-file0 class-file1 ...。
打完jar包以后,假如不需要执行。做个简单的测试吧。假设pkg.jar中包含一个类ClassA,当前目录下有一个ClassB.java文件中import pkg.ClassA; 接下来如果让这能正常工作呢?
方法一:jar xvf pkg.jar ; 即解包到当前目录,简单粗暴。解压后能正常工作,但如果不解压,直接使用jar包呢,目前没有成功,有待进一步了解。
方法二:-cp save-path/pkg.jar 或 -classpath save-path/pkg.jar ;如果用这个方法,那么javac和java都需要带上这个参数。如果-cp多个路径,那么linux下要用分号串联起来,如 -cp save-path/pkg.jar:another-path/anotherpkg.jar:.,最后一个分号后我们跟了一个点号,即当前目录。对于多个路径的顺序是否会对 同名包的引用顺序起到影响,还需要进一步的学习。
方法三:既然-classpath可以,那么将jar包所在的路径加入到CLASSPATH环境变量中也是可以的。-cp save-path/pkg.jar,在CLASSPATH中应该对应为 $CLASSPATH:save-path/pkg.jar,即将save-path/pkg.jar整个作为一体补充到CLASSPATH中。jar包本身就包含着一定的目录结构,因此在将jar包加入CLASSPATH时,pkg.jar作为我们要使用的package的父目录也要加入CLASSPATH。
【疑问】,考虑方法三中所叙述的内容,如果我们使用 jar cvf pkg.jar ./pkg (其中./pkg下包含ClassA)来打jar包,那么ClassA所在的路径应该为pkg.pkg.ClassA,可是这样在方法三的时候能过说的通;但如果我们回到方法一,将jar包直接放在当前目录,不解压,而是将ClassB中import语句改为 import pkg.pkg.ClassA; ,则不能如其的工作。这又是为什么呢?并且这与具体的打jar包时将整个package进行打包,还是将具体文件打包无关。
更进一步,到一个需要执行的包,即使提供运行入口使 java -jar pkg.jar 成功。
主要通过修改Manifest文件,以及命令 jar cfm pkg.jar Manifest /pkg 来实现。
Manifest文件的话,可以通过jar的压包和解压获得。修改的内容为在Manifest文件中添加一条 Main-Class : pkg.Main (如果你在你的包中提供的运行入口与这个类似的话),这里体现入口文件在包中的层次结构。
之后指定新的Manifest文件并重压即可。
如果有多个jar包,可以在当前工作目录下创建一个lib文件夹,再将jar包都丢进去,然后:
javac -cp lib Main.java
java -Djava.ext.libs=lib Main
在实践学习过程中的其他一点发现:
javac 与 java 不同
如果在pkg目录下(假设pkg目录在CLASSPATH下找不到),我们有ClassA.java和Main.java两个文件,两个文件内都有package语句 package pkg; Main中引用到ClassA。如果这时pkg目录是当前目录,那么编译的话则有 javac Main.java,运行的话则有java pkg.Main。如果切换到pkg的上一层目录,那么两条命令将分别变为javac pkg/Main.java 和 java pkg/Main (或 java pkg.Main),即javac始终是跟着目录层次结构走的,而java则是跟着"类路径引用表"走的。如果我们再将工作目录切换一下,比如切换到 xxx (假如有xxx/pkg/Main.java),那么这个时候 javac xxx/pkg/Main.java是没有任何问题的,但java xxx/pkg/Main 则不能运行,因为"类路径引用表"在' . '和CLASSPATH(如果有设置的话)中都找不到xxx/pkg/Main的class文件。这也会产生明明Main.class在当前工作目录下,但java Main却可能报错的问题,因为Main所在的包层次在"类路径引用表"中可能是xxx.yyy.Main之类的。
上面一段我们假设pkg目录在CLASSPATH下找不到,这次改变假设,pkg目录在CLASSPATH下找得到。那么在其他非pkg目录或pkg父目录的目录下,java pkg.Main 可以运行,因为java是跟着"类路径引用表"走的。回到上一段中说的 java pkg/Main 与 java pkg.Main,如果考虑到 ' . ' 是"类路径引用表"中的默认项,那么其实这两者实质是一样的。