Ограничение максимального размера HashMap в Java - PullRequest
30 голосов
/ 09 апреля 2011

Я хочу ограничить максимальный размер HashMap, чтобы использовать метрики для различных алгоритмов хеширования, которые я реализую. Я посмотрел на коэффициент загрузки в одном из перегруженных конструкторов HashMap.

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, чтобы он никогда не увеличивался?

Ответы [ 5 ]

111 голосов
/ 09 апреля 2011

Вы можете создать новый класс, как этот, чтобы ограничить размер 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;
    }
}
35 голосов
/ 09 апреля 2011

Иногда проще, тем лучше.

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

    ...
}
6 голосов
/ 09 апреля 2011

Простое решение обычно является лучшим, поэтому используйте неизменяемое или Неизменяемое hashmap.

Если вы не можете изменить количество элементов, то размер будет исправлен - проблема решена.

2 голосов
/ 27 сентября 2013
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;
    }


}
1 голос
/ 09 апреля 2011

Метод put в классе HashMap отвечает за добавление элементов в 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);
    } 

Asв этом методе вы можете видеть, где размер HashMap изменяется при превышении порога, поэтому я бы попытался расширить класс HashMap и написать свои собственные методы для put и addEntry, чтобы удалить изменение размера.Что-то вроде:

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

Вам необходимо написать свои собственные методы, поскольку put и addEntry не могут быть переопределены, и вам также нужно будет сделать то же самое для putForNullKey, поскольку он вызывается изнутри put.Проверка в put необходима, чтобы убедиться, что мы не пытаемся поместить объект, если таблица заполнена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...