weakHashMap 源码分析

java中4种引用

强引用:
强引用是默认支持,当内存不足的时候,JVM开始垃圾回收,对于强引用的对象,
就算是出现了OOM也不会回收对象。

软引用
一种相对强引用弱化了一些的引用,用java.lang.ref.SoftReference实现,
可以让对象豁免一些垃圾收集。当系统内存充足的时候,不会被回收;
当系统内存不足的时候,会被回收

弱引用

弱引用需要用java.lang.ref.WeakReference实现,它比软引用的生存期更短,
对于弱引用的对象来说,
只要垃圾回收机制一运行,不管JVM的内存空间是否够,
都会回收该对象的占用内存。

虚引用

虚引用要通过java.lang.ref.PhantomReference类来实现,
虚引用不会决定对象的生命周期,如果一个对象只有虚引用,就相当于没有引用,
在任何时候都可能会被垃圾回收器回收。它不能单独使用也不能访问对象,
虚引用必须和引用队列联合使用。

引用类关系

java引用.jpg

expungeStaleEntries entry 对象回收方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ini复制代码private void expungeStaleEntries() 
{
for (Object x; (x = queue.poll()) != null; )
{
// 遍历链表中的元素是否在队列中 如果在 把value =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
// 数量-1
size--;
break;
}
prev = p;
p = next;
}
}
}
}

get 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ini复制代码public V get(Object key) 
{
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable();
int index = indexFor(h, tab.length);
//step1 获取数组的值
Entry<K,V> e = tab[index];
while (e != null)
{
// 如果hash值 key 相同 然后返回value
if (e.hash == h && eq(k, e.get()))
return e.value;
e = e.next;
}
// 否则找不到
return null;
}

maskNull 判断key 是否是Null

1
2
3
4
5
6
vbnet复制代码private static Object maskNull(Object key) 
{
// 空object对象 // 如果是 key 转为 new Object()
private static final Object NULL_KEY = new Object();
return (key == null) ? NULL_KEY : key;
}

hash 散列函数

1
2
3
4
5
6
7
8
9
scss复制代码final int hash(Object k) {
int h = k.hashCode();

// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}

getTable 获取数组 Entry<key,value> 数组

1
2
3
4
5
scss复制代码private Entry<K,V>[] getTable() {
// 回收 value对象
expungeStaleEntries();
return table;
}

indexFor 获取存放数组的位置

1
2
3
4
5
arduino复制代码private static int indexFor(int h, int length) 
{
// h key hash 值 length 数组的个数
return h & (length-1);
}

put key-value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ini复制代码public V put(K key, V value) 
{
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable();
int i = indexFor(h, tab.length);
// 找到存放的数组下标位置
for (Entry<K,V> e = tab[i]; e != null; e = e.next)
{
// 如果当前位置有值 hash 冲突了 然后判断key和hash 值是否相同
// 如果相同 替换value值
if (h == e.hash && eq(k, e.get()))
{
V oldValue = e.value;
if (value != oldValue)
// 如果不相等 替换value
e.value = value;
// 返回原来的值 替换前的value值
return oldValue;
}
}

modCount++;
// 如果这个位置没有值
Entry<K,V> e = tab[i];
// 创建一个Entry对象 然后tab[i]保存这个对象
tab[i] = new Entry<>(k, value, queue, h, e);
if (++size >= threshold)
// 扩容
resize(tab.length * 2);
return null;
}

Entry

1
2
3
4
5
6
7
8
9
10
ini复制代码Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
// key 弱引用 不是value 切记
// 他是判断key 是否被回收了 如果回收了 把value =null
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%