2011-04-08 272 views
23

我想限制HashMap的最大大小,以獲取我正在實現的各種哈希算法的度量。我查看了HashMap的重載構造函數之一中的loadfactor。限制Java中的HashMap的最大大小

HashMap(int initialCapacity, float loadFactor) 

我嘗試設置loadFactor爲0.0f在構造函數(意思是我不希望的HashMap來擴大規模EVER),但javac調用該無效:

Exception in thread "main" java.lang.IllegalArgumentException: Illegal load factor: 0.0 
     at java.util.HashMap.<init>(HashMap.java:177) 
     at hashtables.CustomHash.<init>(Main.java:20) 
     at hashtables.Main.main(Main.java:70) Java Result: 1 

是否有另方式來限制HashMap的大小,所以它不會增長?

+8

當Map已滿並且您嘗試插入另一個元素時會發生什麼? – biziclop 2011-04-08 22:31:53

+0

正如僅供參考,哈希表需要壓縮它們的密鑰空間,因爲您無法保留2^31 * 4字節的內存空間來保存每個可能密鑰的值。因此,散列表通常會截斷散列並將鏈表用於衝突。 loadFactor rougly指示在表開始使用散列的更多位之前鏈接的最大大小。因此,0長度鏈表沒有任何意義:你不能在其中存儲任何東西。 – chacham15 2014-09-12 04:19:29

回答

30

有時候更簡單更好。

public class InstrumentedHashMap<K, V> implements Map<K, V> { 

    private Map<K, V> map; 

    public InstrumentedHashMap() { 
     map = new HashMap<K, V>(); 
    } 

    public boolean put(K key, V value) { 
     if (map.size() >= MAX && !map.containsKey(key)) { 
      return false; 
     } else { 
      map.put(...); 
      return true; 
     } 
    } 

    ... 
} 
+0

@Ishtar,謝謝你。 – Mike 2011-04-08 22:38:41

+0

此答案限制了您的地圖的_maximum_大小。請參閱Margus對更簡單的Map的回答,以防止放入_或刪除條目。 – 2012-07-09 09:31:03

89

您可以創建這樣一個新的類,限制HashMap的大小:

public class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> { 
    private final int maxSize; 

    public MaxSizeHashMap(int maxSize) { 
     this.maxSize = maxSize; 
    } 

    @Override 
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { 
     return size() > maxSize; 
    } 
} 
+11

用於提及LinkedHashMap類的removeEldestEntry(),它的內置*功能用於維護這種類型的地圖!請參閱:http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html#removeEldestEntry(java.util.Map.Entry) – 2012-08-27 20:08:56

+0

這真是太棒了! – 2014-01-30 09:27:18

+3

以前的java鏈接已死 - http://docs.oracle.com/javase/7/docs/api/java/util/LinkedHashMap.html#removeEldestEntry(java.util.Map.Entry) – 2015-11-16 13:08:35

1

在HashMap類的方法put是一個負責添加元素融入到HashMap中和

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); 
    } 

正如你可以在這個方法中看到的是其中的HashMap是如果閾值有蜜蜂調整:它通過調用一個名爲addEntry的方法,其代碼如下做它n超出了,所以我會嘗試擴展類HashMap併爲putaddEntry編寫我自己的方法,以刪除調整大小。喜歡的東西:

package java.util; 

public class MyHashMap<K, V> extends HashMap { 


    private V myPutForNullKey(V value) { 
     for (Entry<K, V> e = table[0]; e != null; e = e.next) { 
      if (e.key == null) { 
       V oldValue = e.value; 
       e.value = value; 
       e.recordAccess(this); 
       return oldValue; 
      } 
     } 
     modCount++; 
     myAddEntry(0, null, value, 0); 
     return null; 
    } 

    public V myPut(K key, V value) { 
     if (key == null) 
      return myPutForNullKey(value); 
     if (size < table.length) { 
      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++; 
      myAddEntry(hash, key, value, i); 
     } 
     return null; 
    } 

    void myAddEntry(int hash, K key, V value, int bucketIndex) { 
     Entry<K, V> e = table[bucketIndex]; 
     table[bucketIndex] = new Entry<K, V>(hash, key, value, e); 
     size++; 
    } 
} 

您需要自putaddEntry寫自己的方法不能被重寫,你還需要爲putForNullKey做同樣的,因爲它被稱爲內put。驗證put需要驗證,如果表已滿,我們不試圖放置一個對象。

6

簡單的解決方案通常是最好的,所以使用unmodifiableImmutable hashmap。

如果您不能更改元素的數量,那麼大小將被固定 - 問題已解決。

+0

我其實很喜歡這個。 – Mike 2012-07-09 13:51:52

+0

當內存中有大量數據需要哈希映射時,最經常使用哈希映射。使用Immutable hashmaps時,內存消耗會成爲一個問題 – 2014-06-02 03:13:13

2
public class Cache { 
    private LinkedHashMap<String, String> Cache = null; 
    private final int cacheSize; 
    private ReadWriteLock readWriteLock=null; 
    public Cache(LinkedHashMap<String, String> psCacheMap, int size) { 
     this.Cache = psCacheMap; 
     cacheSize = size; 
     readWriteLock=new ReentrantReadWriteLock(); 
    } 

    public void put(String sql, String pstmt) throws SQLException{ 
     if(Cache.size() >= cacheSize && cacheSize > 0){ 
      String oldStmt=null; 
      String oldSql = Cache.keySet().iterator().next(); 
      oldStmt = remove(oldSql); 
      oldStmt.inCache(false); 
      oldStmt.close(); 

     } 
     Cache.put(sql, pstmt); 
    } 

    public String get(String sql){ 
     Lock readLock=readWriteLock.readLock(); 
     try{ 
      readLock.lock(); 
      return Cache.get(sql); 
     }finally{ 
      readLock.unlock(); 
     } 
    } 

    public boolean containsKey(String sql){ 
     Lock readLock=readWriteLock.readLock(); 
     try{ 
      readLock.lock(); 
      return Cache.containsKey(sql); 
     }finally{ 
      readLock.unlock(); 
     } 
    } 

    public String remove(String key){ 
     Lock writeLock=readWriteLock.writeLock(); 
     try{ 
      writeLock.lock(); 
      return Cache.remove(key); 
     }finally{ 
      writeLock.unlock(); 
     } 
    } 

    public LinkedHashMap<String, String> getCache() { 
     return Cache; 
    } 

    public void setCache(
      LinkedHashMap<String, String> Cache) { 
     this.Cache = Cache; 
    } 


}