一般來說使用MAP時就算限定了數量
new HashMap<Integer,Integer>(10)
但是在使用put的時候會連帶使用到addEntry
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
然而在addEntry當中會判斷如果MAP中的數量大於限定數量時
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
會去使用resize進行擴充,而擴充的數量是限定的兩倍
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
也就是說就算一開始設定了數量為10,當裡面的元素超過10之後會自動變成20
要解決這個問題最直覺的作法就是去覆寫put
不過看到put原本的內容.....
我沒有把握弄改好..還是不要亂來吧
後來發現HashMap下面還有一個子類別叫做LinkedHashMap
它跟HashMap不同的地方是LinkedHashMap會去紀錄新增的順序,但HashMap不會
LinkedHashMap中有一個函式叫做removeEldestEntry
從字面上來翻譯,就是移除最舊項目
官方API文件也給了一個覆寫範例
private static final int MAX_ENTRIES = 100;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
如果數量超過一百就移除最先put進來的元素
這不就是我們需要的東西嗎!!!
馬上來測試看看
Map<Integer,Integer> h = new LinkedHashMap<Integer,Integer>(){
private static final int MAX_ENTRIES = 10;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
for(int i = 1; i < 21; i++){
h.put(new Integer(i), new Integer(i));
}
System.out.println(h.size());
最後輸出的結果是10
但如果把LinkedHashMap改成HashMap會輸出20