限制Java中HashMap的最大大小

时间:2011-04-08 22:15:54

标签: java hashmap

我想限制HashMap的最大大小,以便对我正在实施的各种哈希算法采用指标。我在HashMap的一个重载构造函数中查看了loadfactor。

HashMap(int initialCapacity, float loadFactor) 

我尝试在构造函数中将loadFactor设置为0.0f(意味着我不希望HashMap的大小增长),但是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大小的方法,因此它不会增长吗?

6 个答案:

答案 0 :(得分:109)

您可以创建一个这样的新类来限制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;
    }
}

答案 1 :(得分:34)

有时候越简单越好。

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(key, value);
             return true;
        }
    }

    ...
}

答案 2 :(得分:6)

简单解决方案通常是最好的,因此请使用unmodifiableImmutable hashmap。

如果你不能改变元素的数量,那么大小将被修复 - 问题解决了。

答案 3 :(得分: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;
    }


}

答案 4 :(得分:2)

我尝试在构造函数中将loadFactor设置为0.0f(这意味着我不希望HashMap的大小变为EVER),但是javac将此称为无效

loadFactor为1表示“在HashMap充满100%之前不要增长”。如果loadFactor为0,则表示“呈指数增长”。

HashMap docs

capacity 是哈希表中存储桶的数量,初始容量只是创建哈希表时的容量。 load factor 是衡量哈希表在自动增加其容量之前的填充程度的度量。当哈希表中的条目数超过负载因子和当前容量的乘积时,哈希表将被重新填充(即,内部数据结构将被重建),因此哈希表具有大约桶数量的两倍。

示例:使用默认设置初始化的HashMap的容量为16,负载系数为0.75。 Capacity * load factor = 16 * 0.75 = 12。因此,将第13个项目添加到HashMap中会使它增长到(大约)32个存储桶。

无效的示例:一个HashMap初始化,其容量为16,负载系数为0。Capacity * load factor = 16 * 0 = 0。因此,每次尝试添加项目都会触发重新哈希和大小翻倍,直到内存用完为止。

您最初想要的东西:

如果初始容量大于最大条目数除以负载因子,则将不会进行任何哈希操作。

如果创建容量为M> N,加载因子为1的HashMap并添加N个项目,则它将不会增长。

答案 5 :(得分:1)

HashMap类中的方法put负责将元素添加到HashMap中,它通过调用名为addEntry的方法来完成,其代码如下:

   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的大小,因此我将尝试扩展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中的验证来验证我们是否在表格已满时尝试放置对象。