首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java JVM、類與物件核心概念深度解析

     編輯:Java 相關知識

Java 核心基石:JVM、類、物件完整解析

理解 JVM 運作機制、類載入過程、物件記憶體佈局,是從「會寫代碼」進階為「資深工程師」的必經之路。本文從流程控制、運算符、類定義、物件實例化、記憶體模型五大面向深度剖析。


一、流程控制與運算符 (語法基礎)

流程控制結構

Java 提供完整的結構化流程控制:

  • 選擇:if-else, switch-case (Java 12+ 支援 switch 表達式、yield)
  • 迴圈:for, while, do-while, 增強 for (for-each)
  • 跳轉:break, continue, return (無 goto)
  • 異常:try-catch-finally, try-with-resources, throw, throws

九九乘法表範例 (右上三角)

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);
  1. 載入類:若未載入,JVM 讀取 Student.class 至方法區,建立 Class<Student> 物件
  2. 分配記憶體:在堆中劃分區域 (TLAB 或指針碰撞),大小 = 實例欄位 + 物件頭 + 對齊填充
  3. 初始化零值:所有欄位設為預設值 (0, null, false)
  4. 設定物件頭:Mark Word (哈希碼、GC 年齡、鎖狀態)、Class 指標 (指向方法區類元數據)
  5. 執行建構子:按順序:父類靜態→父類實例→子類靜態→子類實例→建構子代碼
  6. 回傳引用:將堆地址賦給棧上變數 stu

記憶體佈局 (HotSpot 64 位壓縮指標)

┌─────────────────────────────────────┐
│          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 字節倍數
└─────────────────────────────────────┘

類 vs 物件 vs 參考

概念比喻記憶體關鍵字
類圖紙/模板方法區 (元空間)class
物件/實例依圖紙製造的具體零件堆new
參考變數指向零件的遙控器棧 (局部變數表)類型名 變數名

三、JVM 核心架構

執行時資料區 (JDK 8+)

┌─────────────────────────────────────────────────────────────┐
│                      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+ 在堆中)包含在堆

物件存取定位方式

  • 句柄池:參考 → 句柄池 (實例指針、類型指針) → 實例/類型
  • 直接指針 (HotSpot 預設):參考 → 實例地址 (含類型指針) → 類型元數據

四、類載入機制

雙親委派模型

Bootstrap ClassLoader (C++ 實現) ← 載入 JAVA_HOME/lib/*.jar
    ↑
Extension ClassLoader ← 載入 JAVA_HOME/lib/ext/*.jar
    ↑
Application ClassLoader (系統類載入器) ← 載入 classpath
    ↑
Custom ClassLoader (使用者自定義)
  • 請求向上委派,載入向下執行
  • 破壞雙親委派:Tomcat (WebappClassLoader 先載入戰鬥)、OSGi、JDBC SPI

類生命週期

  1. 載入 → 2. 驗證 → 3. 準備 (靜態變數賦零值) → 4. 解析 (符號引用→直接引用) → 5. 初始化 (<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 程式的靈魂。深入理解物件記憶體佈局、類載入機制、堆棧交互,能讓你在效能調優、記憶體洩漏排查、並發問題診斷中遊刃有餘。知其然,更要知其所以然。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved