我想限制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
大小的方法,因此它不会增长吗?
答案 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)
简单解决方案通常是最好的,因此请使用unmodifiable或Immutable 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,则表示“呈指数增长”。
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类并为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
中的验证来验证我们是否在表格已满时尝试放置对象。