public class Ques1019 {
// 陣列求和
public static int sum(int[] datas) {
int sum = 0;
for (int i = 0; i < datas.length; i++) {
sum += datas[i]; // 位置 1
}
return sum;
}
// List 求和
public static int sum(List datas) {
int sum = 0;
for (int i = 0; i < datas.size(); i++) {
sum += datas.get(i); // 位置 2
}
return sum;
}
}
問題:針對 int 類型陣列與 List 的求和操作,哪個性能更優?為什麼?
陣列版本 (位置 1) 性能顯著優於 List 版本 (位置 2),差距可達 10x - 100x (視 JVM 優化、數據量而定)。
List 存儲的是 Integer 對象引用;datas.get(i) 返回 Integer,參與 += 時觸發 拆箱 (Integer.intValue());sum += ... 結果賦值給 int,無裝箱,但循環內每次 get 都涉及對象頭檢查、方法調用開銷。int[] 直接存儲原始類型值,連續內存佈局,零對象開銷。| 維度 | int[] | List |
|---|---|---|
| 內存結構 | 連續塊,單純 int 值 | 對象數組,每元素指向堆上 Integer 對象 |
| 佔用空間 | 4 bytes × N | ~16 bytes (對象頭) + 4 bytes (值) + 4/8 bytes (引用) ≈ 24-32 bytes/元素 |
| CPU 緩存命中 | 極高 (空間局部性完美) | 低 (間接引用導致緩存未命中、額外內存訪問) |
| GC 壓力 | 無 | 大量短命 Integer 對象 (若非緩存池範圍 -128~127) |
elementData 數組),內聯雖可優化但難以向量化;
Benchmark Mode Cnt Score Error Units
ArraySum.sum avgt 10 1.23 ± 0.05 ms/op
ArrayListSum.sum avgt 10 45.67 ± 1.23 ms/op
// 差距 ~37x
list.parallelStream().mapToInt(Integer::intValue).sum() (多核下可追平陣列);IntArrayList、FastUtil IntArrayList、Guava Ints,內部用 int[],API 兼容 List;for (Integer v : list) sum += v; (foreach 編譯器優化略好於索引 get);IntStream、ToIntFunction 等原始類型流 API。Java 泛型類型擦除機制要求類型參數為引用類型,List 非法。Project Valhalla (Value Types / Primitive Classes) 正在解決此問題,未來將支持 ArrayList 等扁平化集合,實現陣列性能與集合 API 的統一。
性能敏感路徑,優先用基本類型陣列 (int[]、double[] 等) 或專用基本類型集合庫。List 適合業務邏輯層、數據量小、需泛型多態的場景。理解「裝箱/拆箱、內存佈局、JIT 向量化」三大機制,是寫出高性能 Java 代碼的核心內功。