初學 Java 最常遇到的錯誤莫過於 `Exception in thread "main" java.lang.NoClassDefFoundError` 或 `Could not find or load main class`。本文從 JVM 類載入機制出發,系統講解 Classpath 的三種指定方式、包與目錄對應關係、JAR 檔案製作與執行,助你徹底根治類找不到問題。
特殊情況:`java -jar app.jar` 會**忽略所有 Classpath**,僅從該 JAR 的 `MANIFEST.MF` `Class-Path` 屬性載入依賴。
// HelloWorld.java
package pkg;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
目錄結構:
project/ ├── src/ │ └── pkg/ │ └── HelloWorld.java └── classes/ (編譯輸出目錄)
正確編譯與執行:
cd project/src
javac -d ../classes pkg/HelloWorld.java
cd ../classes
java pkg.HelloWorld # 正確:完整類名 pkg.HelloWorld
# java pkg/HelloWorld # 錯誤:視為類名 "pkg/HelloWorld"
cd classes
jar -cvf myapp.jar pkg # 打包 pkg 目錄
jar -cvfm myapp.jar manifest.txt pkg # 指定 Manifest
`manifest.txt` 內容:
Manifest-Version: 1.0 Main-Class: pkg.HelloWorld Class-Path: lib/dependency.jar # 相對路徑
執行:`java -jar myapp.jar` (無需指定 Classpath)。
| 現象 | 原因 | 解決 |
|---|---|---|
| 編譯通過,執行 `NoClassDefFoundError` | 執行時 Classpath 缺少類或依賴 JAR | 檢查 `java -cp` 包含所有依賴目錄/JAR |
| IDE 正常,命令列失敗 | IDE 自動管理 Classpath,命令列未同步 | 導出 IDE 的 Classpath 參考,或用構建工具 |
| 同名類衝突 | 多個 JAR 含相同包路徑類 | 調整 Classpath 順序,或使用模組化 (JPMS) |
| Linux/Mac 冒號 `:` 分隔 | 路徑分隔符平台差異 | Windows 用 `;`,Unix 用 `:` |