今天在學習享元模式 Flyweight Pattern,發現原來Java的Integer
中有用到這個模式。
為了避免以下內容讓你混淆,先記得比較任意兩個Integer
物件時,請使用equals()
方法,不該用==
。
例如下面程式碼,使用Integer.valueOf(int i)
來取得Integer
物件。
Integer integer1 = Integer.valueOf(1);
Integer integer2 = Integer.valueOf(1);
System.out.println(integer1 == integer2); // true
Integer integer3 = Integer.valueOf(128);
Integer integer4 = Integer.valueOf(128);
System.out.println(integer3 == integer4); // false
真是太神奇了,為什麼上下的結果不同?但看了Integer.valueOf()
的原始碼才發現原來其例用享元模式維護了一個靜態的Integer cache[]
的物件池來達到重用的目的。
public final class Integer extends Number implements Comparable<Integer> {
...
private static class IntegerCache {
static final int low = -128; // cache[] 預設的最低範圍
static final int high; // cache[] 的最高範圍
static final Integer cache[]; // <-- 此用來存放重用的Integer物件
static {
// high value may be configured by property
int h = 127; // cache[] 預設的最高範圍值,可透過VM參數XX:AutoBoxCacheMax調整
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) // 判斷cache[]中是否已存在要取得的Integer物件
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
...
}
Integer
初始化的時候有個內部靜態類別IntegerCache
,其靜態成員變數cache[]
預設會生成-128到127的Integer
物件儲存起來。如果呼叫Integer.valueOf()
來取得Integer
物件時,若輸入的參數值落在-128至127的範圍內就會從這個cache[]
取得。
上面範例的integer1
和integer2
輸入參數值(1)落在範圍內,因此皆從cache[]
中返回同一個Integer
物件,所以用==
比較參照位址結果為true。
而integer3
與integer4
的輸入值(128)落在範圍外,所以各自返回一個新的Integer物件,所以用==
比較時,因為所指的參照位址不同,所以結果為false。
也就是說,在Java程式中如果要取得Integer
物件,建議用Integer.valueOf()
來取得,不要用new
的方式,有較好的效能且可減少記憶體的消耗。
引述API說明
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
cache[]
的最大值可透過啟動Java程式時輸入系統參數-Djava.lang.Integer.IntegerCache.high
或XX:AutoBoxCacheMax
來調整。
但總之再強調一次,別使用==
來比較任何物件。
參考:
沒有留言:
張貼留言