本文為 Java 基礎入門 系列文,第 6 篇:
Java 作為全球熱門的程式語言,被廣泛應用於網站開發、Android 應用程式、企業級系統等領域。
對於初學者來說,掌握 Java 的基本結構是踏入開發世界的第一步。
本文將深入解析 主類別(Main Class) 的核心概念、程式執行邏輯,以及常見的檔案命名規則,並透過範例程式碼幫助新手建立扎實的基礎。
建議閱讀本文前,先具備相關概念:
Java 程式的基本結構
類別(Class)與方法(Method)
Java 程式由 類別 組成,每個類別中可包含多個 方法(類似於其他語言中的函式)。
而程式的執行必定從 main 方法開始,這是 Java 虛擬機(JVM)的強制要求。
最小可執行程式範例
以下是一個經典的 Hello, Java! 程式:
public class HelloJava {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}- 執行流程:
JVM 會從main方法開始執行,並輸出Hello, Java!。
為什麼 Java 程式一定要從 main 方法開始?
想像你在玩一款電腦遊戲,每個遊戲都會有個「開始遊戲」的按鈕,按下去後遊戲才會正式運行。
在 Java 裡,這個「開始遊戲」的角色就是 main 方法。
當你執行 Java 程式時,Java 虛擬機(JVM)就像是遊戲的主控系統,它會按照以下步驟來執行程式:
- 啟動 Java 虛擬機(JVM)。
- 找到你寫的 Java 類別(Class)。
- 在類別裡尋找
main方法(因為這是 Java 規定的進入點)。 - 執行
main方法裡的程式碼,開始運作。
如果你的程式裡沒有 main 方法,JVM 會不知道該從哪裡開始,結果就會報錯,導致程式無法執行。
下面是 JVM 執行 Java 程式的過程:
graph TD;
A[啟動 Java 程式] --> B[JVM 啟動]
B --> C{找到 main 方法?}
C -- 是 --> D[執行 main 方法]
D --> E[程式開始運作]
C -- 否 --> F[報錯:找不到 main 方法!]
F --> G[程式終止]
為什麼 main 方法一定要是 static?
在 Java 中,所有的程式碼都必須寫在類別(Class)裡。
但有一個問題——當 JVM 啟動時,還沒有任何物件存在,那麼 JVM 要怎麼執行程式呢?
Java 方法的執行方式
在 Java 裡,一般的方法(非 static 方法)都必須透過物件來呼叫,例如:
class MyClass {
void sayHello() { // 這是一個非 static 方法
System.out.println("Hello!");
}
public static void main(String[] args) {
MyClass obj = new MyClass(); // 先建立物件
obj.sayHello(); // 再透過物件呼叫方法
}
}
在這個例子中,sayHello() 不是 static,所以我們必須先用 new MyClass() 建立 MyClass 的物件,然後才能呼叫 sayHello() 方法。
但問題是,當 Java 程式剛開始執行時,JVM 還沒辦法知道該怎麼建立物件!
JVM 啟動時還沒有物件
當 JVM 啟動 Java 應用程式時,它只知道要執行某個類別,但它不會自動建立物件,因為它不知道該怎麼做。
如果 main 不是 static,那 JVM 就會遇到這個問題:
- JVM 需要呼叫
main方法開始執行程式。 - 但如果
main不是static,JVM 需要先建立這個類別的物件。 - 然而,JVM 並不知道該怎麼建立物件,因為可能需要傳入參數,或是類別的建構子(Constructor)可能有特別的邏輯。
- 結果 JVM 進入「無限迴圈」的困境,程式無法啟動。
所以,為了讓 JVM 能夠順利啟動程式,main 必須是 static,這樣 JVM 才能直接執行它,而不需要先建立物件。
static 讓 main 可以直接執行
當一個方法被標記為 static,代表它是類別層級的方法,不屬於任何物件。
也就是說,我們可以直接透過類別名稱呼叫它,而不需要建立物件。
舉個例子:
class MyClass {
static void sayHello() { // 這是一個 static 方法
System.out.println("Hello!");
}
public static void main(String[] args) {
MyClass.sayHello(); // 直接用類別名稱呼叫,不需要建立物件
}
}
在這裡,sayHello() 是 static,所以我們不需要 new MyClass(),可以直接用 MyClass.sayHello() 來執行它。
同樣地,main 方法被設為 static,JVM 就可以直接執行它,而不需要先建立物件。
如果 main 不是 static 會發生什麼事?
如果我們嘗試這樣寫:
class MyClass {
void main(String[] args) { // 不是 static
System.out.println("Hello, Java!");
}
}
當我們執行這個程式時,JVM 會報錯:
Error: Main method is not static in class MyClass, please define the main method as:
public static void main(String[] args)
這是因為 JVM 需要 static 方法來當作程式的進入點,如果 main 不是 static,它就無法正確執行程式。
多個 static 方法不會衝突
static 方法只是屬於類別本身的方法,你可以在類別內定義多個 static 方法,它們彼此獨立,互不影響。例如:
class MyClass {
static void sayHello() {
System.out.println("Hello!");
}
static void sayGoodbye() {
System.out.println("Goodbye!");
}
public static void main(String[] args) {
MyClass.sayHello(); // 呼叫 sayHello()
MyClass.sayGoodbye(); // 呼叫 sayGoodbye()
}
}
執行結果
Hello!
Goodbye!這裡 sayHello() 和 sayGoodbye() 都是 static,我們可以直接用 MyClass.sayHello() 和 MyClass.sayGoodbye() 來呼叫它們,不需要建立物件。
JVM 只會執行 main 方法
即使你定義了多個 static 方法,JVM 在執行 Java 程式時,只會尋找 public static void main(String[] args) 這個方法作為進入點。
其他 static 方法不會自動執行,除非 main 方法主動呼叫它們。
示範:有多個 static 方法,但 JVM 只執行 main
class MyClass {
static void methodA() {
System.out.println("這是 methodA");
}
static void methodB() {
System.out.println("這是 methodB");
}
public static void main(String[] args) {
System.out.println("程式開始執行");
}
}
執行結果
程式開始執行這裡 methodA() 和 methodB() 不會自動執行,因為 JVM 只會執行 main 方法,而 main 方法裡並沒有呼叫這兩個方法。
main 方法可以主動呼叫其他 static 方法
如果你希望其他 static 方法執行,你需要在 main 方法內明確地呼叫它們。例如:
class MyClass {
static void methodA() {
System.out.println("這是 methodA");
}
static void methodB() {
System.out.println("這是 methodB");
}
public static void main(String[] args) {
System.out.println("程式開始執行");
methodA(); // 呼叫 methodA
methodB(); // 呼叫 methodB
}
}
執行結果
程式開始執行
這是 methodA
這是 methodB這次 methodA() 和 methodB() 都有被 main 方法呼叫,所以它們會被執行。
為什麼 JVM 不能自動建立物件來執行 main?
有人可能會問:「JVM 為什麼不乾脆自己 new 一個物件來呼叫 main 呢?」
有幾個原因:
類別的建構子可能需要參數
class MyClass {
MyClass(int x) {} // 需要參數
void main(String[] args) {
System.out.println("Hello!");
}
}在這種情況下,JVM 不知道應該傳入什麼數值來建立 MyClass 的物件,所以無法自動執行 main。
類別可能有特殊的初始化邏輯
class MyClass {
private MyClass() {} // 私有建構子,禁止建立物件
void main(String[] args) {
System.out.println("Hello!");
}
}如果建構子是 private,JVM 根本無法建立物件,因此 main 不能是一般的方法。
物件建立可能會影響效能
Java 的設計目標之一是高效能和靈活性,如果 JVM 在每次啟動程式時都要自動建立物件,那麼對於一些大型專案來說,這可能會造成額外的開銷,降低執行效率。
public class 的關鍵作用
public class 的定義
public class HelloJava 的結構包含三個部分:
- public:表示類別是公開的,允許其他類別存取。
- class:宣告一個類別。
- HelloJava:類別名稱,需遵守命名慣例(首字母大寫)。
檔案名稱的強制規則
Java 要求 public class 的名稱必須與 .java 檔案名稱完全一致。
- ✅ 正確範例:類別名
HelloJava→ 檔案名HelloJava.java - ❌ 錯誤範例:類別名
HelloJava→ 檔案名Test.java
錯誤示範與解決方案
若將以下程式存為 Test.java:
public class HelloJava { // 類別名稱與檔案名稱不符
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}編譯時會出現錯誤:
Test.java:1: error: class HelloJava is public, should be declared in a file named HelloJava.java.class 與 .java 的關係
一個 .java 檔案能產生多個 .class 檔案
當你在一個 .java 檔案內定義多個類別時,Java 會為每個類別產生對應的 .class 檔案,無論這些類別是否是 public。
範例:一個 .java 產生多個 .class
檔案名稱:Test.java
// 這個類別沒有 public,所以檔案名稱不必是 HelloWorld
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
// 另一個類別
class AnotherClass {
void sayHello() {
System.out.println("這是 AnotherClass");
}
}
編譯這個 .java 檔案
當我們執行:
javac Test.java
Java 會產生兩個 .class 檔案:
HelloWorld.class
AnotherClass.class
這是因為:
javac會自動為.java檔案內的每個類別生成對應的.class檔案。- 每個
.class檔案的名稱,會與該類別的名稱相同。
執行哪個 .class 檔案?
雖然 Test.java 產生了兩個 .class 檔案,但我們執行 Java 程式時,必須指定 main 方法所在的類別,也就是:
java HelloWorld執行結果
Hello, World!
但如果我們嘗試執行:
java AnotherClass會報錯:
Error: Could not find or load main class AnotherClass<br>這是因為 AnotherClass 裡沒有 main 方法,所以 JVM 不知道從哪裡開始執行程式。
如果有 public 類別,檔案名稱必須與 public class 相同
Java 允許多個類別定義在同一個 .java 檔案內,但只能有一個 public 類別,且檔案名稱必須與這個 public class 名稱一致。
範例
檔案名稱:MainClass.java
// 這是 public 類別,所以檔案名稱必須是 MainClass.java
public class MainClass {
public static void main(String[] args) {
System.out.println("這是 MainClass");
}
}
// 這些不是 public,所以它們的名稱不受檔案名稱限制
class AnotherClass {
void sayHello() {
System.out.println("這是 AnotherClass");
}
}
class ThirdClass {
void saySomething() {
System.out.println("這是 ThirdClass");
}
}
編譯 MainClass.java
javac MainClass.java這會產生:
MainClass.class
AnotherClass.class
ThirdClass.classMainClass.class→ 對應public class MainClassAnotherClass.class→ 對應class AnotherClassThirdClass.class→ 對應class ThirdClass
執行
java MainClass輸出:
這是 MainClass如果嘗試:
java AnotherClass則會報錯,因為 AnotherClass 沒有 main 方法。
為什麼 public class 的名稱必須與 .java 檔案名稱完全一致?
在 Java 中,如果一個類別(class)被宣告為 public,那麼它的檔案名稱(.java 檔案)必須與這個 public class 的名稱相同,這是 Java 編譯器強制要求的規則。
確保 Java 檔案和類別名稱一致,方便管理與存取
Java 設計之初,就考慮到大型專案的可讀性與管理性。
要求 public class 名稱與 .java 檔名一致,可以讓開發者透過檔案名稱,就能快速找到對應的類別。
舉個例子,如果你有一個 public class HelloWorld,它的檔案名稱必須是 HelloWorld.java,這樣一來:
- 你在檔案總管或 IDE 裡看到
HelloWorld.java,就能立刻知道這個檔案裡面定義的是HelloWorld類別。 - 當你編譯
HelloWorld.java時,產生的.class檔案會是HelloWorld.class,這樣 JVM 也能按照預期去載入這個類別。
如果不這樣規定,開發者可能會用不相關的檔名,例如 MyFile.java 裡面放 public class HelloWorld,這會讓程式變得難以管理和閱讀。
Java 編譯機制的限制
當 Java 編譯一個 .java 檔案時,它會根據檔案名稱來尋找 public class,並產生對應的 .class 檔案。例如:
// 檔案名稱:HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
執行 javac HelloWorld.java 會產生:
HelloWorld.class如果檔案名稱和 public class 名稱不同,例如:
// 檔案名稱:Test.java
public class HelloWorld { // 不匹配的類別名稱
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
編譯時會發生錯誤:
Error: Class HelloWorld is public, should be declared in a file named HelloWorld.java
這是因為 Java 編譯器會根據 Test.java 這個檔案名稱,預期找到一個 public class Test,但實際上它卻找到了 public class HelloWorld,導致編譯錯誤。
JVM 載入類別時的要求
當你執行 Java 程式時,JVM 會根據 main 方法所在的類別名稱,去尋找對應的 .class 檔案。例如:
java HelloWorld這時候 JVM 會去找 HelloWorld.class 這個編譯好的類別。
如果 Java 允許 public class 的名稱與 .java 檔案名稱不同,就可能發生以下問題:
- JVM 可能找不到對應的
.class檔案,因為.class檔案的名稱是根據public class來決定的,而不是.java檔案名稱。 - 開發者很容易搞混,例如
java Test但實際上Test.class對應的類別名稱卻是HelloWorld,導致執行時出錯。
為了避免這種問題,Java 規定 public class 的名稱與 .java 檔案名稱一致,這樣 JVM 就能根據類別名稱正確找到對應的 .class 檔案並執行。
非 public 類別的情況
如果一個 .java 檔案內的類別沒有宣告為 public,那麼這個檔案的名稱可以跟類別名稱不一致。例如:
// 檔案名稱:Test.java
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
這樣是可以編譯的,因為 HelloWorld 沒有 public,Java 不會強制要求 Test.java 必須跟 HelloWorld 同名。
不過,這時候你不能直接用 java Test 來執行程式,而是要用 java HelloWorld,因為 JVM 會根據 HelloWorld.class 來載入程式。
如果一個 .java 檔案內有多個類別,只能有一個 public 類別,而且檔案名稱必須與這個 public 類別名稱一致。
例如:
// 檔案名稱:MainClass.java
public class MainClass {
public static void main(String[] args) {
System.out.println("這是主類別 MainClass");
}
}
class AnotherClass {
void sayHello() {
System.out.println("這是副類別 AnotherClass");
}
}
這是合法的,因為:
MainClass是public,所以檔案名稱必須是MainClass.java。AnotherClass不是public,所以它可以有不同的名稱。- 執行時只能用
java MainClass,不能用java AnotherClass。
總結:主類別與 main 方法的必要性
主類別的核心作用
主類別是 Java 程式的 入口點(Entry Point),負責:
- 提供
main方法供 JVM 啟動程式。 - 初始化其他物件與邏輯。
- 處理輸入/輸出操作。
沒有 main 方法會怎樣?
若嘗試執行以下類別:
class Helper {
void greet() {
System.out.println("Hello!");
}
}會出現錯誤:
Error: Main method not found in class Helperpublic 修飾詞的迷思
主類別 不一定要是 public,只要包含 main 方法即可:
class MainClass { // 非 public 類別
public static void main(String[] args) {
System.out.println("執行成功!");
}
}但需注意:檔案名稱仍需與類別名稱一致(此例為 MainClass.java)。
常見問題與實戰技巧
快速除錯指南
| 錯誤類型 | 解決方案 |
|---|---|
| 類別名稱與檔案名稱不符 | 檢查 public class 名稱是否正確 |
| 缺少 main 方法 | 確認是否定義 public static void main |
拼字錯誤(如 String[] args) | 檢查方法簽名是否完全正確 |
命名慣例與最佳實踐
- 類別名稱使用 大駝峰式命名法(如
MainClass)。 - 方法名稱使用 小駝峰式命名法(如
sayHello)。 - 檔案名稱與 public class 名稱嚴格一致。