是檔案格式也是打包工具
JAR
(Java ARchive) 是 Java 的 library 的檔案格式, 也是 Java 打包 JAR 檔案的工具, 附在 JDK 裡面.
JAR
檔案 它的副檔名通常是 .jar, 雖然並沒有規定一定要用這樣的副檔名, 官方文件上也特別提到可以用其他的副檔名, 但是變更副檔名似乎並沒有好處.
.jar
的內容,
可以包含
.class (編譯過的 java byte code), .java (java 的原始碼), 或是其他的 .jar, 以及 resource (text, image,
...).
事實上, .jar 就是一個 zip 檔. 如果把它 rename 成 .zip, 可以把它解壓縮出來. 無論和 java 有無關係, 都可以放到 .jar 裡. 就算是一個 windows 的執行程式, .exe, 也可以用 jar 這個工具程式, 把它放到 .jar 檔案中.
package
雖然大部份的文件, 在介紹 jar 時, 都不會提到 package, 但是如果沒有 package, 就算打包成 jar 也無法使用.
package
在
Java 裡面,
是一組
class 的合集, class 之間, 並不一定要有關係, 只是放在一起而已. 一個 Java 程式, 可能包含或引用的 class 可能有數十或數百個, 名稱衝突就成了一個很大的問題. 為了解決這個問題, 引用了樹狀的命名結構. 譬如說, Red Face 這個公司的 excel library 就可以採用 com.redface.excel 作為 package 的命名. 而這個 package 中的 File, Worksheet, Page 等 class, 就可以命名為 com.redface.excel.File,
com.redface.excel.Worksheet, .... 這樣就不會和 java.util.io.File 這個 class 衝突. 就可以解決命名的問題. 除非 Red Face 這個公司的網址有變動, 或是公司的內控有問題, 否則不會有命名衝突的問題.
因為 package 解決了命名的問題, 所以 .jar 可以把亂七八糟的東西都放在一個檔案中.
How
to make a jar from command line
我們用這個 java 程式, 來做例子, 把它放到 jar 中.
InJar.java
package
jarlib;
public
class InJar {public static void main(String[] args) {
System.out.println("I'm in Jar");
}
public void doIt(){
System.out.println("InJar doing ..." );
}
}
package jarlib;
這一個敘述, 說明 InJar 這個 class, 是在 jarlib 的 package 中. 程式的其他部份都很簡單, 就不多說了.
javac
-d . InJar.java
然後在 command line 用 javac 來編譯它. -d 的意思是指定把編譯的結果 (.class) 檔案, 放到路徑中. 我們現在只需要放到目前目錄, 所以就是 .編譯後, 我們可以發現, 在目前的路徑下, 多了一個 jarlib 的目錄. 我們編譯完成的InJar.class 就放在這裡面. 也就是說, 它會根據我們的 package 結構, 建立相對應的路徑. 如果我們在程式中的 pacakge 敘述, 修改成
package jarlib.jar.lib;
那麼建立出來的路徑, 就會是 jarlib/jar/lib
jar
cf jarlib.jar jarlib
這一個 jar 的命令, 是 create file, 建立 jarlib.jar, 把 jarlib 路徑下的檔案, 都放到 jarlib.jar 中. 用解壓縮軟體, 例如 7-zip 可以直接解開這個 .jar
解開 jarlib.jar 這個檔案, 除了我們指定的 jarlib 的目錄, 還多了一個
META-INF
的目錄.
這個 META-INF 的目錄, 裡面只有一個檔案, MANIFEST.MF, 這個檔案的內容如下 :
Manifest-Version:
1.0
Created-By:
1.7.0_09 (Oracle Corporation)
當我們要製作可以執行的 jar, java 的執行環境, 就是從這裡找出要執行的 class 作為進入點.
How
to use a jar from java code
我們需要另外一個程式來使用這個 jar 檔案.
Tester.java
import
jarlib.InJar;
public
class Tester {public static void main(String[] args) {
System.out.println("I'm Tester");
InJar in_jar = new InJar();
in_jar.doIt();
}
}
javac
-cp ./jarlib.jar Tester.java
編譯測試程式的時候, 需要指定含入的 library, 也就是 jar. 這裡是指定目前目錄(.) 的 jarlib.jar.
以下命令的結果, 在這個例子中是相同的
javac
-cp jarlib.jar Tester.javajavac -classpath jarlib.jar Tester.java
javac -classpath ./jarlib.jar Tester.java
java
-cp .;jarlib.jar Tester
接下來執行 Tester 這個測試程式. 這邊需要把 jarlib.jar 插入 class path, 這邊的語法, 和平台有關:Windows :
Linux & Mac :
java -classpath .:jarlib.jar Tester
輸出的結果如下
java -cp .;jarlib.jar
Tester
I'm
TesterInJar doing ...
Create Executable Jar
要讓 Jar 變成可以執行, 需要在 Jar 中定義當這個 jar 被執行的時候, 它的進入點為何. 這邊我們需要定義一個 InJar.MF, 這個檔案的內容如下, 記得最後要多加一行空白 (多按一次 enter)
Manifest-Version:
1.0
Main-Class:
jarlib.InJar
把它放在 jarlib 這個目錄中. (javac -d . InJar.java 這個命令可以建立這個目錄, 並把 InJar.class 放在這個目錄中)
然後執行
jar
cmf ./jarlib/InJar.MF jarlib.jar ./jarlib/InJar.class
就可以把 InJar.class 打包,變成一個可以執行的 jar 檔
java
-jar jarlib.jar
在執行 jar 的時候, 需要多加一個 -jar 參數, 然後就可以順利執行了. 打開 jarlib.jar, 可以看到裡面多了 MANIFEST.MF. 在 MANIFEST.MF 的最後, 多了一行 Main-Class:
jarlib.InJar, 這一行就是指定這一個 jar 的進入點, 當這一個 jar 被執行時, java VM 會在這個檔案中尋找 Main-Class, 再在 Main-Class 中尋找 main 這個 function, 並且執行.
Manifest-Version:
1.0
Created-By:
1.7.0_09 (Oracle Corporation)Main-Class: jarlib.InJar