Подтвердить что ты не робот

Ограничение максимального размера HashMap в Java

Я хочу ограничить максимальный размер HashMap, чтобы принимать метрики для множества алгоритмов хеширования, которые я реализую. Я посмотрел на loadfactor в одном из 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, чтобы он никогда не увеличивался?

4b9b3361

Ответ 1

Иногда проще.

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

    ...
}

Ответ 2

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

Ответ 3

Простое решение, как правило, лучшее, поэтому используйте unmodifiable или Immutable hashmap.

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

Ответ 4

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


}

Ответ 5

Метод 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);
    } 

Как вы можете видеть в этом методе, где 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 требуется для проверки того, что мы не пытаемся поместить объект, если таблица заполнена.