陷阱 - 過度使用原始包裝型別效率低下

考慮這兩段程式碼:

int a = 1000;
int b = a + 1;

Integer a = 1000;
Integer b = a + 1;

問題:哪個版本更有效?

答:這兩個版本看起來幾乎相同,但第一個版本比第二個版本效率更高。

第二個版本使用表示使用更多空間的數字,並依賴於幕後自動裝箱和自動拆箱。實際上第二個版本直接等同於以下程式碼:

Integer a = Integer.valueOf(1000);               // box 1000
Integer b = Integer.valueOf(a.intValue() + 1);   // unbox 1000, add 1, box 1001

將此與使用 int 的其他版本相比較,當使用 Integer 時,顯然有三個額外的方法呼叫。在 valueOf 的情況下,每個呼叫都將建立並初始化一個新的 Integer 物件。所有這些額外的裝箱和拆箱工作可能使第二個版本比第一個版本慢一個數量級。

除此之外,第二個版本是在每個 valueOf 呼叫中在堆上分配物件。雖然空間利用率是特定於平臺的,但對於每個 Integer 物件,它可能在 16 位元組的區域內。相比之下,int 版本需要零額外的堆空間,假設 ab 是區域性變數。

原語比其盒裝等價物更快的另一個重要原因是它們各自的陣列型別如何在記憶體中佈局。

如果以 int[]Integer[] 為例,在 int[] 的情況下,int 在記憶體中連續排列。但是在 Integer[] 的情況下,它不是佈局的值,而是對 Integer 物件的引用(指標),而這些物件又包含實際的 int 值。

除了是一個額外的間接級別,當迭代值時,這對於快取區域性性來說可能是一個很大的障礙。在 int[] 的情況下,CPU 可以立即將陣列中的所有值提取到它的快取中,因為它們在記憶體中是連續的。但是對於 Integer[],CPU 可能必須為每個元素執行額外的記憶體提取,因為該陣列僅包含對實際值的引用。

簡而言之,在 CPU 和記憶體資源中使用原始包裝型別相對昂貴。不必要地使用它們是有效的。