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