weakHashMap 源码分析

348 阅读3分钟

java中4种引用

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

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

弱引用

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

虚引用

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

引用类关系

java引用.jpg

expungeStaleEntries entry 对象回收方法

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 方法

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

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 散列函数

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> 数组

private Entry<K,V>[] getTable() {
   // 回收 value对象
    expungeStaleEntries();
    return table;
}

indexFor 获取存放数组的位置

private static int indexFor(int h, int length) 
{
    // h key hash 值  length 数组的个数
    return h & (length-1);
}

put key-value

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

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