雖然會用 Eclipse, 但工具很龐大, 啟動要一點時間, 所以我一直都習慣用 DOS 畫面執行 Java. 但編譯後可能會產生多個 class 檔 (例如內部類別), 攜帶不方便, 而且要使用者打開 DOS 視窗, 敲入一長串執行指令, 在 GUI 為王道的今天, 實在太委屈了, 應該將整個程式壓縮成單一的可執行 jar 檔較好. 下面將以之前測試 JTextField 時的一個範例檔案為例來說明.
# Java Swing 測試 : JLabel 與文字欄位
這篇文章被 Google 翻譯弄亂了, 因為小狐貍們也跟我一樣用 Chrome, 結果菁菁有一次啟動了 "Google 翻譯" 我不知道, 存檔後才發現它把程式碼也翻譯了, 目前暫時還沒時間去一一修復, 擱著吧. 我們要用的是其中幾乎無損的範例 9 (JTextField6.java), 但此處要做個修改, 就是為了製作 jar 檔時抓相關的 class 方便, 希望將編譯出來的 class 檔都集中放在指定目錄中, 這就要用到 package 觀念了, 我們在原來的 JTextField6.java 前面加上 package mypackage :
package mypackage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JTextField6 implements ActionListener {
JFrame f;
JTextField text1,text2;
JButton cut, copy, paste;
public static void main(String argv[]) {
new JTextField6();
}
public JTextField6() {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JTextField6");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
text1=new JTextField();
text1.setBounds(20,20,200,25);
cp.add(text1);
cut=new JButton("剪下");
cut.setBounds(20,70,60,25);
cut.addActionListener(this);
cp.add(cut);
copy=new JButton("複製");
copy.setBounds(90,70,60,25);
copy.addActionListener(this);
cp.add(copy);
paste=new JButton("貼上");
paste.setBounds(160,70,60,25);
paste.addActionListener(this);
cp.add(paste);
text2=new JTextField();
text2.setBounds(20,120,200,25);
cp.add(text2);
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
});
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==cut) {text1.cut();}
else if (e.getSource()==copy) {text1.copy();}
else if (e.getSource()==paste) {text2.paste();}
}
}
編譯時要加點料, 不是 javac JTextField6.java, 這樣仍然是在目前目錄下產生 class 檔, 亦即有沒有加 package 都一樣. 要讓 class 檔放在 package 目錄下, 必須這樣編譯 :
javac -d . JTextField6.java
注意, 多了一個選項 -d 與小數點, 表示要在目前目錄下建立一個 package 所指定之子目錄, 並將產生的 class 檔放在裡面. 例如 JTextField6.java 是在 G:\java\JT 下, 則編譯後, 會建立一個 mypackage 子目錄, 並將產生的兩個 class 檔 : JTextField6.class 與 JTextField6$1.class 放在此子目錄下 :
一個專案通常由多個 java 檔組成, 可以將這些 java 檔都指定為相同 package 名稱, 然後只用下面指令一次編譯全部該專案的 java 檔, 產生的 class 檔就全部放在 package 所指定的子目錄下 :
javac -d . *.java
然後在工作目錄, 即 java 檔所在目錄, 下達壓縮指令 :
jar cvf JTextField6.jar mypackage
第二個參數是壓縮後的檔案, 可自訂; 但最後一個參數則必須是要壓縮的 package 目錄名. 這樣就會在工作目錄下產生 JTextField6.jar 檔案 :
L:\Java\JT>jar cvf JTextField6.jar mypackage
已新增資訊清單
新增: mypackage/ (讀=0)(寫=0)(儲存 0%)
新增: mypackage/JTextField6$1.class (讀=801)(寫=557)(壓縮 30%)
新增: mypackage/JTextField6.class (讀=2132)(寫=1191)(壓縮 44%)
使用 RAR 或 Winzip 解壓縮此 jar 檔就可以得到 class 檔案群. 事實上 jar 檔就是 zip 檔, 直接把副檔名 .jar 改成 .zip 解壓縮如下 :
可見 jar 指令除了將 package 目錄壓進去外, 還加了一個 META-INF 目錄, 裡面有一個 MENIFEST.MF 檔案, 內容如下 :
Manifest-Version: 1.0
Created-By: 1.7.0_51 (Oracle Corporation)
執行 jar 檔指令如下 :
java -cp JTextField6.jar mypackage/JTextField6
必須指定 package 名稱以及主 class 名稱才行. 但是在檔案總管直接點擊 jar 檔是無法執行的, 那要怎麼做呢? 其實只要在壓縮 jar 檔時, 在上面那個 MANIFEST.MF 檔案裡添加 Main-Class 屬性, 指定主類別名稱就可以了.
首先我們要準備一個文字檔, 例如 manifest.txt, 其內容如下 :
Main-Class: mypackage.JTextField6
注意, 打完須 enter, 否則無效. 這裡主類別是在 mypackage 套件下, 所以務必註明套件名稱, 如果只寫 JTextField6 將找不到主類別. 然後重新壓縮 :
L:\Java\JT>jar cvmf manifest.txt JTextField6.jar mypackage
已新增資訊清單
新增: mypackage/ (讀=0)(寫=0)(儲存 0%)
新增: mypackage/JTextField6$1.class (讀=801)(寫=557)(壓縮 30%)
新增: mypackage/JTextField6.class (讀=2132)(寫=1191)(壓縮 44%)
這樣就可以直接用 -jar 選項執行 jar 檔了.
L:\Java\JT>java -jar JTextField6.jar
而且直接在檔案總管點擊 jar 檔也可以執行了.
把 jar 副檔名改為 zip 去看壓縮檔中 META-INF 目錄下的 MANIFEST.MF 內容 :
Manifest-Version: 1.0
Created-By: 1.7.0_51 (Oracle Corporation)
Main-Class: mypackage.JTextField6
可見在壓縮時, jar 工具程式會讀取我們指定的 manifest.txt 檔內容, 然後寫入 MANIFEX.MF 檔裡. 當然, 如果不要設 package 也是可以的, 把專案中全部要用到 class 都放在同一目錄下, 然後於 manifest.txt 檔案中指定主類別, 然後在 jar 指令中列舉各 class 即可 :
jar cvmf manifest.txt ABC.jar A.class B.class C.class
參考資料 :
# Java Gossip: 製作 Executable JAR
# 可執行的 jar 檔
沒有留言:
張貼留言