理解 JVM 運作機制、類載入過程、物件記憶體佈局,是從「會寫代碼」進階為「資深工程師」的必經之路。本文從流程控制、運算符、類定義、物件實例化、記憶體模型五大面向深度剖析。
Java 提供完整的結構化流程控制:
public class MultiplicationTable {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
if (j < i) {
System.out.print(" "); // 8 空格對齊
} else {
System.out.printf("%d×%d=%2d ", i, j, i * j);
}
}
System.out.println();
}
}
}
| 類別 | 運算符 | 說明 |
|---|---|---|
| 算術 | + - * / % | 基本四則運算、取餘 |
| ++ -- | 前綴/後綴自增減 | |
| + - (一元) | 正負號 | |
| = += -= *= /= %= | 賦值與複合賦值 | |
| 關係 | == != > < >= <= | 比較,回傳 boolean |
| instanceof | 類型檢查 (Java 16+ 模式匹配) | |
| 邏輯 | && \|\| ! ^ | 短路與、或、非、異或 |
| 位元 | & | ^ ~ | 位元與、或、異或、取反 |
| << >> >>> | 左移、有號右移、無號右移 | |
| 三元 | ? : | condition ? expr1 : expr2 |
後綴 ++ -- → 一元 + - ~ ! ++ -- → 算術 * / % → + - → 移位 << >> >>> → 關係 < <= > >= instanceof → 等值 == != → 位元 & → 位元 ^ → 位元 | → 邏輯 && → 邏輯 || → 三元 ? : → 賦值 = += -= ... → Lambda ->
public class Student {
// 1. 欄位
private String name; // 實例欄位
private int age;
private static String school = "Java 高中"; // 靜態欄位 (類層級)
// 2. 建構子
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 3. 方法
public void study() { System.out.println(name + " 正在學習 Java"); }
public static void assembly() { System.out.println("全校集會"); }
// 4. 內部類、枚舉、註解等...
}
Student stu = new Student("小明", 18);
Student.class 至方法區,建立 Class<Student> 物件stu┌─────────────────────────────────────┐ │ Object Header (12/16 bytes) │ ├─────────────────────────────────────┤ │ Mark Word (8/12 bytes) │ ← 哈希碼、GC 分代年齡、鎖標記、偏向鎖 Thread ID │ Class Pointer (4 bytes, 壓縮指標) │ ← 指向方法區 Class 元數據 ├─────────────────────────────────────┤ │ Instance Fields │ │ name (4 bytes, 參考) │ │ age (4 bytes, int) │ ├─────────────────────────────────────┤ │ Padding (對齊填充, 0-7 bytes) │ ← 確保物件大小為 8 字節倍數 └─────────────────────────────────────┘
| 概念 | 比喻 | 記憶體 | 關鍵字 |
|---|---|---|---|
| 類 | 圖紙/模板 | 方法區 (元空間) | class |
| 物件/實例 | 依圖紙製造的具體零件 | 堆 | new |
| 參考變數 | 指向零件的遙控器 | 棧 (局部變數表) | 類型名 變數名 |
┌─────────────────────────────────────────────────────────────┐ │ JVM 進程記憶體 │ ├─────────────────┬─────────────────┬─────────────────────────┤ │ 堆 │ 棧 │ 方法區 │ │ (Heap) │ (JVM Stack) │ (Metaspace / 元空間) │ │ ┌──────────┐ │ ┌──────────┐ │ ┌────────────────────┐ │ │ │ Young Gen│ │ │ Thread 1 │ │ │ 類元數據 │ │ │ │ Eden/S0/S1│ │ │ Frame... │ │ │ 執行時常數池 │ │ │ ├──────────┤ │ ├──────────┤ │ │ 靜態變數 │ │ │ │ Old Gen │ │ │ Thread 2 │ │ │ JIT 編譯代碼 │ │ │ └──────────┘ │ │ Frame... │ │ └────────────────────┘ │ │ │ └──────────┘ │ │ ├─────────────────┴─────────────────┴─────────────────────────┤ │ 直接記憶體 / Native Memory (NIO Buffer, JNI, Metaspace) │ └─────────────────────────────────────────────────────────────┘
| 區域 | 線程私有 | 主要內容 | OOM 風險 |
|---|---|---|---|
| 程式計數器 (PC Register) | 是 | 當前執行指令位址 | 極低 |
| JVM 虛擬機棧 | 是 | 棧幀 (局部變數表、操作數棧、動態連接、返回地址) | StackOverflowError |
| 本地方法棧 | 是 | Native 方法調用 | StackOverflowError |
| 堆 | 否 | 所有物件實例、陣列 | OutOfMemoryError: Java heap space |
| 方法區/元空間 | 否 | 類元數據、常數、靜態變數、JIT 代碼 | OutOfMemoryError: Metaspace |
| 執行時常數池 | 否 | 字面量、符號引用 (Class 常數池運行時表示) | 包含在 Metaspace |
| 字串常數池 | 否 | String.intern() 字串、字面量 (JDK 7+ 在堆中) | 包含在堆 |
Bootstrap ClassLoader (C++ 實現) ← 載入 JAVA_HOME/lib/*.jar
↑
Extension ClassLoader ← 載入 JAVA_HOME/lib/ext/*.jar
↑
Application ClassLoader (系統類載入器) ← 載入 classpath
↑
Custom ClassLoader (使用者自定義)
<clinit> 賦值、靜態塊) → 6. 使用 → 7. 卸載import java.util.Scanner;
public class DaysInMonth {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("輸入年份: ");
int year = sc.nextInt();
System.out.print("輸入月份: ");
int month = sc.nextInt();
int days = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30;
case 2 -> (isLeapYear(year) ? 29 : 28);
default -> throw new IllegalArgumentException("月份錯誤: " + month);
};
System.out.printf("%d 年 %d 月有 %d 天%n", year, month, days);
}
static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
}
從語法細節到 JVM 底層,類與物件是 Java 程式的靈魂。深入理解物件記憶體佈局、類載入機制、堆棧交互,能讓你在效能調優、記憶體洩漏排查、並發問題診斷中遊刃有餘。知其然,更要知其所以然。