Java 語言長期以來在處理小型數據載體時面臨一個效能瓶頸:所有的類別實例(Class Instance)都具有身分識別(Identity)。這意味著意味著無論一個物件僅僅是代表一個座標點(Point)或一個顏色值(Color),JVM 都必須為其分配一個獨立的記憶體位址,並透過指標(Pointer)來存取。這種設計導致了記憶體碎片化,增加了垃圾回收(Garbage Collection)的壓力,且由於數據在記憶體中是不連續的,嚴重影響了 CPU 快取(Cache)的命中率。為了打破這個限制,OpenJDK 推動了 Project Valhalla 計畫,而最新整合進 JDK 28 的 JEP 401 預覽功能,正式引入了 Value Objects(值物件)的概念。
背景與核心問題:身分識別的成本
在傳統的 Java 物件模型中,兩個內容完全相同的物件,只要是由不同的建構子呼叫產生的,它們在記憶體中就是不同的實體。這種身分識別對於管理複雜業務實體(如 User 或 Account)至關重要,但對於純粹攜帶數據的小型類別來說,身分識別不僅毫無意義,反而成為效能負擔。
目前的 JVM 雖然嘗試透過逃逸分析(Escape Analysis)來優化記憶體分配,但這種優化具有不可預測性,且一旦物件被儲存在陣列或欄位中,優化便會失效。開發者在實務上常需要面對這種矛盾:想要物件導向的封裝便利,卻必須承受因過多指標跳轉而導致的效能損失。JEP 401 的目標就是定義一種不具備身分識別的類別,讓 JVM 能像處理基本型別(Primitive Types)一樣處理物件。
Value Objects 的運作機制
透過在類別宣告中使用 value 修飾詞,開發者可以將其定義為 Value Class。一旦類別被標記為值物件,它將遵循一套更嚴格的規則以確保其行為符合值語義。首先,值物件的所有實例欄位都隱含為 final,且在物件建構完成前,所有欄位必須被賦值,這由 JEP 539 的嚴格欄位初始化機制在位元組碼(Bytecode)層級進行驗證。
此外,由於值物件沒有身分識別,因此不允許在其實例方法上使用 synchronized 關鍵字,因為同步鎖(Lock)必須依附於一個具備唯一身分的物件上。值得注意的是,Java 的 Record 類別同樣可以使用 value 修飾詞,使其成為更高效的數據載體。
最顯著的語義改變發生在 == 運算子的行為上。對於傳統的 identity 物件,== 依然比對記憶體位址;但對於 Value Objects,== 現在會比對兩個物件是否屬於同一類別且所有欄位的值均相等。如果欄位本身也是參考型別,則會遞迴地使用 == 進行比對。這使得開發者在處理值物件時,能以更直覺的方式確認兩個物件的內容是否一致,而不需要強迫呼叫 equals 方法。
記憶體優化與實務影響
引入 Value Objects 的終極目的不在於改變語法,而在於讓 JVM 能進行記憶體扁平化(Flattening)優化。在目前的模型中,一個物件陣列實際上是存放了一系列指標,每個指標指向記憶體中分散的物件。而當 JVM 識別出某個類別是 Value Object 時,它可以將其標量化(Scalarize),直接將物件的欄位值展開儲存在記憶體中,或者將其扁平化地存放在陣列元素中,而不需要額外的指標。
這種扁平化能大幅提升空間利用率並增強局部性(Locality),讓 CPU 能一次讀取連續的數據塊。雖然這種優化受限於平台原子的操作限制(例如在典型平台上,編碼大小可能限制在 64 位元含 null 標記),且在 JIT 編譯器優化前的預熱階段仍會回退到普通分配,但長遠來看,這將顯著降低記憶體開銷。
限制與遷移考量
儘管 Value Objects 帶來了效能潛力,但它也對現有 API 造成了衝擊。由於值物件沒有身分,任何嘗試為其建立 Reference(弱引用或強引用)的操作都會拋出 IdentityException。此外,JDK 28 中部分內建的類別(如基本型別的包裝類別 Wrapper Classes 和 LocalDate)在開啟預覽功能時會轉變為值物件,這意味著開發者必須重新評估對這些類別使用 == 的邏輯。
安全方面,由於 == 現在會檢查內部欄位,這可能會間接暴露私有欄位的數值。同時,如果兩個巨大的值物件樹狀結構進行 == 比對,可能會導致執行時間不可控。因此,官方建議即使有了新的 == 行為,在需要比對物件代表的邏輯狀態時,依然應優先使用 equals 方法。
總結來說,JEP 401 是 Project Valhalla 的重要里程碑,它試圖在維持 Java 強型別特性的同時,消除不必要的身分識別成本,讓 Java 在處理高吞吐量數據時能擁有接近 C 語言結構體(Struct)的效能表現。
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。