為什麼說不變模式可以提高性能
在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對象。