在Java中基礎型別的包裝類都是不可變的類,如Boolean、Byte、Character、Double、Float、Integer、Long、Short,另外還有String。
這些類建立的例項都是不可以變的例項。
//Integer類程式碼 JDK1.8
public final class Integer extends Number implements Comparable<Integer> {
private final int value;
public Integer(int value) {
this.value = value;
}
}
可以看到Integer類是final型別的不可被繼承,其封裝的int值是也是final的。這就導致了例項建立後我們沒有其他辦法去修改這個int值,所以說Integer物件是不可變物件。
那不可變物件又是如何提高效能的呢,這裡看Integer的valueOf方法。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer在呼叫valueOf時是先從IntegerCache查詢物件,如果沒有才去建立一個新的物件,有的話就直接將引用指向這個物件。IntegerCache是個靜態內部類,儲存了-128到127的值的物件陣列。
因為Integer物件是不可變的,這樣這個快取陣列就可以在多個執行緒中進行共享,減少Integer物件的建立。
比如你通過一個ORM框架查詢出1萬條人員資料,人員資料使用Person類封裝,Person類有一個欄位Integer sex儲存性別資料,1男2女。例項化這1萬個Person類的時候就可以將這1萬個Integer sex分別指向Integer(1)和Integer(2)的記憶體地址。如果張三的當前性別是男,你想改成女,那就把sex的引用指向快取中Integer(2)的記憶體地址。這樣的話在沒有建立任何額外的Integer例項的情況下,達到了節省記憶體的目的。
反過來看,如果物件是可變的,就沒法做快取了。物件內部int值變化會導致所有對這個物件的引用不安全,就必須為每個Person建立一個Integer sex物件。
包裝型別的快取機制和字串的快取機制都是用的這個思想,就是減少物件的建立數量。