在继承AbstractMap中的子类中除了Hashmap外还有WeakHashmap。
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
在这里我们可以看到 WeakHashmap和Hashmap一样都是继承AbstractMap类 的,实现的接口也是Map接口。
接下来我们看一下他的一些常量。
private static final int DEFAULT_INITIAL_CAPACITY = 16; //默认大小
private static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量
private static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认的填充因子
在这里我们可以看到 是基于Entry(存储键值对)数组实现的。
Entry<K,V>[] table;
这里还有一个队列,在后面我们会说他的作用。
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
public WeakHashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Initial Capacity: "+
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load factor: "+
loadFactor);
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
table = newTable(capacity);
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
}
这里是WeakHashmap 的构造方法,需要传入两个数据,默认大小和填充因子。然后多Capacity做合法性判断和限制,然后是填充因子的判断。最后会new一个table。
private Entry<K,V>[] newTable(int n) {
return (Entry<K,V>[]) new Entry<?,?>[n];
}
这是new出来的table,就是一个Entry类型的数组。
重点来了
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
这段很长的代码,里边出现了前面的queue 。这里的x是从queue中出来的,前提能实现queue.poll()方法。然后,这是加了一个锁吗?再然后,是吧x给Entry节点。再调用indexFor()方法。
private static int indexFor(int h, int length) {
return h & (length-1);
}
在算哈希值。这个方法。然后就是对散列表的操作。注意有一句e.value = null; // Help GC
这里有用到GC回收。这是和Hashmap不同的。这里的queue是ReferenceQueue类型的。我们来说一下ReferenceQueue。
Reference
Reference主要负责内存中的一个状态。他和Java的虚拟机,垃圾回收器有关。Referenc类将内存分为四个状态,
Activite,>一般来说,内存一开始被分配的都是Activie
Pending,>快要放入队列中的对象
Enqueued,——》已经被内存回收的对象,并把它放入队列中,方便查看某个对象是否被回收。
inacvite.——》最终状态。
ReferenceQueue
垃圾回收器将已注册的引用对象添加到队列中。
总的来说,WeakHashmap 存储的是弱键。是当没有节点(数据)失去引用后,会被GC回收。这是自动的。原因就是使用的queue出数据,而queue是一个ReferenceQueue类型的。