2011-04-08 269 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; 
    } 


}