要讓 JAR 檔案支援雙點擊執行,必須在資訊清單中指定主類別,並確保 JAR 關聯正確的 Java 執行環境。以下為標準步驟與常見陷阱。
建立純文字檔 manifest.mf (或 .mf/.mft),內容如下:
Main-Class: com.example.MainClass Class-Path: lib/dependency1.jar lib/dependency2.jar
關鍵規則:
Main-Class: 後必須有一個空格,接著完整類別名稱 (含套件名)。Class-Path: 列出相對路徑 (空格分隔),路徑相對於 JAR 所在目錄。# 基本語法: jar cvfm<輸入檔案...> jar cvfm MyApp.jar manifest.mf -C bin/ . # 從 bin/ 目錄打包所有類別與資源 # 或指定具體檔案 jar cvfm MyApp.jar manifest.mf com/example/*.class resources/*.properties
參數說明:
c:建立新檔案v:顯示詳細過程f:指定輸出檔名m:引入自訂 Manifest| 指令 | 說明 |
|---|---|
jar cvfm app.jar manifest.mf *.class | 目前目錄所有 .class 檔 |
jar cvfm app.jar manifest.mf *.class *.java | 包含原始碼 (可選) |
jar cvfm app.jar manifest.mf *.* | 目前目錄所有有副檔名的檔案 |
jar cvfm app.jar manifest.mf * | 目前目錄所有檔案 (含無副檔名) |
jar cvfm app.jar manifest.mf -C build/classes . | 從 build/classes 目錄遞迴打包 (推薦) |
# 檢查 Manifest 內容 jar tf app.jar META-INF/MANIFEST.MF # 或直接解壓查看 # 執行 java -jar app.jar # 雙擊執行需作業系統已關聯 .jar -> javaw.exe (Windows) / java (Linux/Mac)
Maven (pom.xml):
org.apache.maven.plugins maven-jar-plugin 3.4.2 com.example.MainClass true lib/ ${maven.build.timestamp} org.apache.maven.plugins maven-dependency-plugin 3.6.0 copy-dependencies package copy-dependencies ${project.build.directory}/lib
執行 mvn clean package 產生 target/app.jar 並自動複製依賴至 target/lib/。
Gradle (build.gradle):
plugins { id 'application' }
application { mainClass = 'com.example.MainClass' }
tasks.named('jar') {
manifest {
attributes 'Main-Class': 'com.example.MainClass',
'Class-Path': configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(' ')
}
}
tasks.register('copyLibs', Copy) {
from configurations.runtimeClasspath
into 'build/libs/lib'
}
tasks.named('build').configure { dependsOn 'copyLibs' }
| 現象 | 可能原因 | 解決方法 |
|---|---|---|
| 雙擊無反應 | .jar 未關聯 javaw.exe | Windows: assoc .jar=jarfile ftype jarfile="C:\Path\javaw.exe" -jar "%1" %* |
| 找不到主類別 | Manifest 缺少 Main-Class 或格式錯誤 | 檢查 jar tf app.jar META-INF/MANIFEST.MF,確認有空格與換行 |
| ClassNotFoundException (依賴) | Class-Path 路徑錯誤或依賴未複製 | 使用 Maven/Gradle 自動管理,或手動建立 lib/ 目錄放置依賴 |
| 載入資源檔失敗 | 使用 File 而非 ClassLoader 讀取 | 改用 getClass().getResourceAsStream("/config.properties") |
若專案使用 module-info.java,打包為模組化 JAR:
jar --create --file app.jar --main-class com.example.MainClass -C mods/com.example .
執行時需指定模組路徑:
java --module-path libs --module com.example/com.example.MainClass
或打包為模組化執行映像 (jlink) 產生不需 JRE 的原生啟動器。