Java 新手入門:理解主類別與程式基本結構

Published February 15, 2025 by 徐培鈞
程式語言

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)就像是遊戲的主控系統,它會按照以下步驟來執行程式:

  1. 啟動 Java 虛擬機(JVM)。
  2. 找到你寫的 Java 類別(Class)。
  3. 在類別裡尋找 main 方法(因為這是 Java 規定的進入點)。
  4. 執行 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 就會遇到這個問題:

  1. JVM 需要呼叫 main 方法開始執行程式。
  2. 但如果 main 不是 static,JVM 需要先建立這個類別的物件。
  3. 然而,JVM 並不知道該怎麼建立物件,因為可能需要傳入參數,或是類別的建構子(Constructor)可能有特別的邏輯。
  4. 結果 JVM 進入「無限迴圈」的困境,程式無法啟動。

所以,為了讓 JVM 能夠順利啟動程式,main 必須是 static,這樣 JVM 才能直接執行它,而不需要先建立物件。

staticmain 可以直接執行

當一個方法被標記為 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.class
  • MainClass.class → 對應 public class MainClass
  • AnotherClass.class → 對應 class AnotherClass
  • ThirdClass.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 檔案名稱不同,就可能發生以下問題:

  1. JVM 可能找不到對應的 .class 檔案,因為 .class 檔案的名稱是根據 public class 來決定的,而不是 .java 檔案名稱。
  2. 開發者很容易搞混,例如 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");
    }
}

這是合法的,因為:

  • MainClasspublic,所以檔案名稱必須是 MainClass.java
  • AnotherClass 不是 public,所以它可以有不同的名稱。
  • 執行時只能用 java MainClass,不能用 java AnotherClass

總結:主類別與 main 方法的必要性

主類別的核心作用

主類別是 Java 程式的 入口點(Entry Point),負責:

  1. 提供 main 方法供 JVM 啟動程式。
  2. 初始化其他物件與邏輯。
  3. 處理輸入/輸出操作。

沒有 main 方法會怎樣?

若嘗試執行以下類別:

class Helper {
    void greet() {
        System.out.println("Hello!");
    }
}

會出現錯誤:

Error: Main method not found in class Helper

public 修飾詞的迷思

主類別 不一定要是 public,只要包含 main 方法即可:

class MainClass { // 非 public 類別
    public static void main(String[] args) {
        System.out.println("執行成功!");
    }
}

但需注意:檔案名稱仍需與類別名稱一致(此例為 MainClass.java)。


常見問題與實戰技巧

快速除錯指南

解決方案檢查 public class 名稱是否正確
解決方案確認是否定義 public static void main
解決方案檢查方法簽名是否完全正確

命名慣例與最佳實踐

  1. 類別名稱使用 大駝峰式命名法(如 MainClass)。
  2. 方法名稱使用 小駝峰式命名法(如 sayHello)。
  3. 檔案名稱與 public class 名稱嚴格一致。