java_集合体系之WeakHashMap详解、源码及示例——11

java_集合体系之WeakHashMap详解、源码及示例——11

 

一:WeakHashMap结构图


                java_集合体系之WeakHashMap详解、源码及示例——11_第1张图片


简单说明:

        1、上图中虚线且无依赖字样、说明是直接实现的接口

        2、虚线但是有依赖字样、说明此类依赖与接口、但不是直接实现接口

        3、实线是继承关系、类继承类、接口继承接口

        4、继承AbstractMap、以键值对的形式存储、操作元素

        5、实现WeakReference接口、具有弱引用对象特性

        6、实现ReferenceQueue接口、具有将引用向其注册引用功能、进而使用其提供的方法操作引用。

        7、上面两个接口通常会一起使用、用来处理弱引用对象、比如本文中的WeakHashMap。

补充:弱引用(WeakReference)   

        如果一个对象只具有弱引用,那就类似于可有可无的生活用品。只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回 收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 

 

二:WeakHashMap类简介:


        1、 基于哈希表的Map结构的实现

        2、线程不安全

        3、内部映射无序

        4、允许值为null的key和value

    5、当WeakHashMap中的键不再有其他的强引用的时候、此键表示的键值对会被GC回收、这里可能有点难理解、后面会有更详细的说明。


三:WeakHashMap API


1、构造方法

 

// 默认构造函数。
WeakHashMap()

// 指定“容量大小”的构造函数
WeakHashMap(int capacity)

// 指定“容量大小”和“加载因子”的构造函数
WeakHashMap(int capacity, float loadFactor)

// 包含“子Map”的构造函数
WeakHashMap(Map<? extends K, ? extends V> map)


2、一般方法

 

void                   clear()
Object                 clone()
boolean                containsKey(Object key)
boolean                containsValue(Object value)
Set<Entry<K, V>>       entrySet()
V                      get(Object key)
boolean                isEmpty()
Set<K>                 keySet()
V                      put(K key, V value)
void                   putAll(Map<? extends K, ? extends V> map)
V                      remove(Object key)
int                    size()
Collection<V>          values()
   

四:WeakHashMap 源码分析


说明:

        1、对哈希表要有简单的认识、

        2、WeakHashMap是通过“拉链法”解决哈希冲突的

        3、理解WeakHashMap源码中的关键部分、Entry实体类的行为、属性。Entry的存储方式、WeakHashMap的扩容方式、WeakHashMap内部关于获取新的hash code的算法。

        4、理解他如何实现弱引用的。

        5、理解三种视图的内部获取的方式。

        6、WeakHashMap的实例有两个参数影响其性能:初始容量加载因子容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

        7、默认加载因子 (0.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数WeakHashMap 类的操作中,包括 get 和put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

        8、  如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

        9、如果很多映射关系要存储在 WeakHashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

当使用WeakHashMap对外提供的存入键值对的方法put()、putAll()时、WeakHashMap内部会检测WeakHashMap容量是否达到阀值、进而判断是否需要扩容。与此有关的一系列方法源码汇总(包括内部方法)

 

package com.chy.collection.core;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;


public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {

	/** 初始化HashMap时默认的容量、必须是2的幂*/
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    /** HashMap容量最大值、必须是2幂、并且要小于2的30次方、如果容量超过这个值、将会被这个值代替*/
    private static final int MAXIMUM_CAPACITY = 1 << 30;

    /** 默认加载因子*/
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /** 存储数据的Entry数组,长度是2的幂。Entry的本质是一个单向链表*/
    private Entry[] table;

    /** 当前HashMap中键值对的总数*/
    private int size;

    /** 当前HashMap中键值对的总数*/
    private int threshold;

    /** 加载因子的实际值*/
    private final float loadFactor;

    /** 引用队列、垃圾回收器将已注册的引用对象添加到该队列中。
     *	在这里结合WeakReference使用、用于记录WeakHashMap中的弱引用键 
     */
    private final ReferenceQueue<K> queue = new ReferenceQueue<K>();

    private volatile int modCount;

    /** 使用指定的容量、加载因子初始化WeakHashMap*/
    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 = new Entry[capacity];
        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
    }
    /** 使用指定初始容量、默认加载因子创建WeakHashMap*/
    public WeakHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    /**使用默认初始容量 16、默认加载因子0.75创建WeakHashMap*/
    public WeakHashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
    }
    /** 创建包含指定传入Map的所有键值对创建WeakHashMap、使用默认加载因子、使用处理后的容量*/
    public WeakHashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
             DEFAULT_LOAD_FACTOR);
        putAll(m);
    }

    // internal utilities

    /** 当key为null时使用的值
     *  因为WeakHashMap中允许“null的key”,若直接插入“null的key”,将其当作弱引用时,会被删除。
     */
    private static final Object NULL_KEY = new Object();

    /** 当key为null时使用的值特殊处理、将其使用静态不可变常量“new Object()”代替
     *	在put中会被调用、防止将null作为的key被当作“弱引用键”被GC回收。 
     */
    private static Object maskNull(Object key) {
        return (key == null ? NULL_KEY : key);
    }

    /** 
     * 还原对“null的key”的特殊处理
     * 在get(key)中被调用、返回key为null的value。	 
     */
    private static <K> K unmaskNull(Object key) {
        return (K) (key == NULL_KEY ? null : key);
    }

    /** 判断“x”和“y”是否相等*/
    static boolean eq(Object x, Object y) {
        return x == y || x.equals(y);
    }

    //根据传入的hash值与数组长度获取hash值代表的键在table中的索引
    static int indexFor(int h, int length) {
    	// 保证返回值的索引值小于length
        return h & (length-1);
    }

    /** 消除table中“弱引用键”对应的键值对
     *  1、当WeakHashMap中某个“弱引用的key”由于没有再被引用而被GC收回时、被回收的“弱引用key”也被会被添加到"ReferenceQueue(queue)"中。
     * 
     */
    private void expungeStaleEntries() {
    	Entry<K,V> e;
        while ( (e = (Entry<K,V>) queue.poll()) != null) {
            int h = e.hash;
            int i = indexFor(h, 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;
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                    break;
                }
                prev = p;
                p = next;
            }
        }
    }

    /** 消除table中“弱引用键”对应的键值对、每次使用WeakHashMap时后会先调用此方法*/
    private Entry[] getTable() {
        expungeStaleEntries();
        return table;
    }
    /** 返回当前HashMap中键值对个数*/
    public int size() {
        if (size == 0)
            return 0;
        expungeStaleEntries();
        return size;
    }
    /** 判断当前HashMap是否为空*/
    public boolean isEmpty() {
        return size() == 0;
    }
    /** 获取指定key对应的value*/
    public V get(Object key) {
        Object k = maskNull(key);
        int h = HashMap.hash(k.hashCode());
        Entry[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null) {
            if (e.hash == h && eq(k, e.get()))
                return e.value;
            e = e.next;
        }
        return null;
    }
    /** 是否包含传入的 key*/
    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }
    /** 获取指定key所代表的映射Entry*/
    Entry<K,V> getEntry(Object key) {
        Object k = maskNull(key);
        int h = HashMap.hash(k.hashCode());
        Entry[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null && !(e.hash == h && eq(k, e.get())))
            e = e.next;
        return e;
    }
    /** 将指定键值对放入HashMap中、如果HashMap中存在key、则替换key映射的value*/
    public V put(K key, V value) {
        K k = (K) maskNull(key);
        int h = HashMap.hash(k.hashCode());
        Entry[] tab = getTable();
        int i = indexFor(h, tab.length);

        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
            if (h == e.hash && eq(k, e.get())) {
                V oldValue = e.value;
                if (value != oldValue)
                    e.value = value;
                return oldValue;
            }
        }

        modCount++;
        Entry<K,V> e = tab[i];
        tab[i] = new Entry<K,V>(k, value, queue, h, e);
        if (++size >= threshold)
            resize(tab.length * 2);
        return null;
    }
    /** rehash当前WeakHashMap、此方法会在WeakHashMap容量达到阀值的时候自动调用、*/
    void resize(int newCapacity) {
        Entry[] oldTable = getTable();
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(oldTable, newTable);
        table = newTable;

        /*
         * If ignoring null elements and processing ref queue caused massive
         * shrinkage, then restore old table.  This should be rare, but avoids
         * unbounded expansion of garbage-filled tables.
         */
        if (size >= threshold / 2) {
            threshold = (int)(newCapacity * loadFactor);
        } else {
            expungeStaleEntries();
            transfer(newTable, oldTable);
            table = oldTable;
        }
    }

    /** 将原来table中所有元素转移到新的table中*/
    private void transfer(Entry[] src, Entry[] dest) {
        for (int j = 0; j < src.length; ++j) {
            Entry<K,V> e = src[j];
            src[j] = null;
            while (e != null) {
                Entry<K,V> next = e.next;
                Object key = e.get();
                if (key == null) {
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                } else {
                    int i = indexFor(e.hash, dest.length);
                    e.next = dest[i];
                    dest[i] = e;
                }
                e = next;
            }
        }
    }
    /** 将m中所有键值对存储到HashMap中*/
    public void putAll(Map<? extends K, ? extends V> m) {
        int numKeysToBeAdded = m.size();
        if (numKeysToBeAdded == 0)
            return;

        /*
         * 计算容量是否满足添加元素条件
         * 若不够则将原来容量扩容2倍
         */
        if (numKeysToBeAdded > threshold) {
            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
            if (targetCapacity > MAXIMUM_CAPACITY)
                targetCapacity = MAXIMUM_CAPACITY;
            int newCapacity = table.length;
            while (newCapacity < targetCapacity)
                newCapacity <<= 1;
            if (newCapacity > table.length)
                resize(newCapacity);
        }
        //使用迭代器迭代m中每个元素、然后添加到HashMap中
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }
    /** 删除“键为key”的元素*/
    public V remove(Object key) {
        Object k = maskNull(key);
        int h = HashMap.hash(k.hashCode());
        Entry[] tab = getTable();
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && eq(k, e.get())) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return e.value;
            }
            prev = e;
            e = next;
        }

        return null;
    }



    /** Special version of remove needed by Entry set */
    Entry<K,V> removeMapping(Object o) {
        if (!(o instanceof Map.Entry))
            return null;
        Entry[] tab = getTable();
        Map.Entry entry = (Map.Entry)o;
        Object k = maskNull(entry.getKey());
        int h = HashMap.hash(k.hashCode());
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && e.equals(entry)) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return e;
            }
            prev = e;
            e = next;
        }

        return null;
    }
    /** 删除所有键值对*/
    public void clear() {
        // clear out ref queue. We don't need to expunge entries
        // since table is getting cleared.
        while (queue.poll() != null)
            ;

        modCount++;
        Entry[] tab = table;
        for (int i = 0; i < tab.length; ++i)
            tab[i] = null;
        size = 0;

        // Allocation of array may have caused GC, which may have caused
        // additional entries to go stale.  Removing these entries from the
        // reference queue will make them eligible for reclamation.
        while (queue.poll() != null)
            ;
    }
    /** 删除所有键值对*/
	public void clear() {
	    // clear out ref queue. We don't need to expunge entries
	    // since table is getting cleared.
	    while (queue.poll() != null)
	        ;
	
	    modCount++;
	    Entry[] tab = table;
	    for (int i = 0; i < tab.length; ++i)
	        tab[i] = null;
	    size = 0;
	
	    // Allocation of array may have caused GC, which may have caused
	    // additional entries to go stale.  Removing these entries from the
	    // reference queue will make them eligible for reclamation.
	    while (queue.poll() != null)
	        ;
	}
	/** 判断是否包含value*/
    public boolean containsValue(Object value) {
	if (value==null)
            return containsNullValue();

	Entry[] tab = getTable();
        for (int i = tab.length ; i-- > 0 ;)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (value.equals(e.value))
                    return true;
	return false;
    }

    /** 是否包含null*/
    private boolean containsNullValue() {
	Entry[] tab = getTable();
        for (int i = tab.length ; i-- > 0 ;)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (e.value==null)
                    return true;
	return false;
    }

    /**
     * Entry是单向链表。
     * 他继承WeakReference、使得可以使用Entry的key作为弱引用、并且向ReferenceQueue(queue)中注册该引用、以便后期检测WeakHashMap中key的引用类型、进而调整WeakHashMap
     * 它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数
     */
    private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
        private V value;
        private final int hash;
        private Entry<K,V> next;

        /** 创建一个实体Entry、并将Entry的key以弱引用的形式向给定的ReferenceQueue注册*/
        Entry(K key, V value, ReferenceQueue<K> queue, int hash, Entry<K,V> next) {
        	//创建引用给定对象的新的弱引用,并向给定队列注册该引用。
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

        public K getKey() {
            return WeakHashMap.<K>unmaskNull(get());
        }

        public V getValue() {
            return value;
        }

        public V setValue(V newValue) {
	    V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public int hashCode() {
            Object k = getKey();
            Object v = getValue();
            return  ((k==null ? 0 : k.hashCode()) ^
                     (v==null ? 0 : v.hashCode()));
        }

        public String toString() {
            return getKey() + "=" + getValue();
        }
    }

    /**
     * 抽象类、用于迭代WeakHashMap、
     * 包含三种视图的迭代“keySet”、“valueCollection”、“Entry<K, V>”三个迭代器
     */
    private abstract class HashIterator<T> implements Iterator<T> {
        int index;
        Entry<K,V> entry = null;
        Entry<K,V> lastReturned = null;
        int expectedModCount = modCount;

        /** 下一个键(强引用、不会消失*/
        Object nextKey = null;

        /** 当前键(强引用、不会消失*/
        Object currentKey = null;

        HashIterator() {
            index = (size() != 0 ? table.length : 0);
        }

        //查看是否有下一个
        public boolean hasNext() {
            Entry[] t = table;

            while (nextKey == null) {
                Entry<K,V> e = entry;
                int i = index;
                while (e == null && i > 0)
                    e = t[--i];
                entry = e;
                index = i;
                if (e == null) {
                    currentKey = null;
                    return false;
                }
                nextKey = e.get(); // hold on to key in strong ref
                if (nextKey == null)
                    entry = entry.next;
            }
            return true;
        }

        //获取下一个元素
        protected Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (nextKey == null && !hasNext())
                throw new NoSuchElementException();

            lastReturned = entry;
            entry = entry.next;
            currentKey = nextKey;
            nextKey = null;
            return lastReturned;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            WeakHashMap.this.remove(currentKey);
            expectedModCount = modCount;
            lastReturned = null;
            currentKey = null;
        }
    }
    // value的迭代器
    private class ValueIterator extends HashIterator<V> {
        public V next() {
            return nextEntry().value;
        }
    }
    // key的迭代器
    private class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

    // Entry的迭代器
    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }

    // Views

    private transient Set<Map.Entry<K,V>> entrySet = null;

    public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
    }

    private class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return new KeyIterator();
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public boolean contains(Object o) {
            return containsKey(o);
        }

        public boolean remove(Object o) {
            if (containsKey(o)) {
                WeakHashMap.this.remove(o);
                return true;
            }
            else
                return false;
        }

        public void clear() {
            WeakHashMap.this.clear();
        }
    }

    public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null ?  vs : (values = new Values()));
    }

    private class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return new ValueIterator();
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public boolean contains(Object o) {
            return containsValue(o);
        }

        public void clear() {
            WeakHashMap.this.clear();
        }
    }

    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es = entrySet;
        return es != null ? es : (entrySet = new EntrySet());
    }

    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator();
        }

        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k = e.getKey();
            Entry candidate = getEntry(e.getKey());
            return candidate != null && candidate.equals(e);
        }

        public boolean remove(Object o) {
            return removeMapping(o) != null;
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public void clear() {
            WeakHashMap.this.clear();
        }

    //深度克隆、提供toArray()、toArray(T[] a)方法    
	private List<Map.Entry<K,V>> deepCopy() {
	    List<Map.Entry<K,V>> list = new ArrayList<Map.Entry<K,V>>(size());
	    for (Map.Entry<K,V> e : this)
		list.add(new AbstractMap.SimpleEntry<K,V>(e));
	    return list;
	}

        public Object[] toArray() {
            return deepCopy().toArray();
        }

        public <T> T[] toArray(T[] a) {
            return deepCopy().toArray(a);
        }
    }
}

总结 :

        1、数据结构:WeakHashMap是以哈希表的形式存储数据的、并且是通过“拉链法”解决冲突、WeakHashMap中存储的Entry实现了Map.Entry<K, V>、WeakReference、并且借助WeakReference的构造方法将WeakReference与ReferenceQueue结合起来、使用Entry的key作为弱引用键注册到ReferenceQueue中。Entry源码:


    /**
     * Entry是单向链表。
     * 他继承WeakReference、使得可以使用Entry的key作为弱引用、并且向ReferenceQueue(queue)中注册该引用、以便后期检测WeakHashMap中key的引用类型、进而调整WeakHashMap
     * 它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数
     */
    private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
        private V value;
        private final int hash;
        private Entry<K,V> next;

        /** 创建一个实体Entry、并将Entry的key以弱引用的形式向给定的ReferenceQueue注册*/
        Entry(K key, V value, ReferenceQueue<K> queue, int hash, Entry<K,V> next) {
        	//调用WeakReference构造方法创建引用给定对象的新的弱引用,并向给定队列注册该引用。
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

        public K getKey() {
            return WeakHashMap.<K>unmaskNull(get());
        }

        public V getValue() {
            return value;
        }

        public V setValue(V newValue) {
	    V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public int hashCode() {
            Object k = getKey();
            Object v = getValue();
            return  ((k==null ? 0 : k.hashCode()) ^
                     (v==null ? 0 : v.hashCode()));
        }

        public String toString() {
            return getKey() + "=" + getValue();
        }
    }


 

        关于key作为弱引用的实现流程图:


         


到此完成WeakHashMap的键的弱引用的构造。

 

        2、关于WeakHashMap的使用:

        分成三部分来说明:添加、删除、其他、主要是WeakHashMap允许键为null的值、其内部对键为null进行了特殊处理、其他的则是每次使用WeakHashMap的时候都要将WeakHashMap中弱引用的键值对删除、即同步table和ReferenceQueue中存放的引用指向的键值对。

                a)  添加:

 

                java_集合体系之WeakHashMap详解、源码及示例——11_第2张图片


 

                b)  删除:


                 java_集合体系之WeakHashMap详解、源码及示例——11_第3张图片


                c)  其他:通过关键同步源码来说明

 

    /** 消除table中“弱引用键”对应的键值对
     *  1、当WeakHashMap中某个“弱引用的key”由于没有再被引用而被GC收回时、被回收的“弱引用key”也被会被添加到"ReferenceQueue(queue)"中。
     * 
     */
    private void expungeStaleEntries() {
    	Entry<K,V> e;
        while ( (e = (Entry<K,V>) queue.poll()) != null) {
            int h = e.hash;
            int i = indexFor(h, 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;
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                    break;
                }
                prev = p;
                p = next;
            }
        }
    }

    /** 消除table中“弱引用键”对应的键值对、每次使用WeakHashMap时后会先调用此方法*/
    private Entry[] getTable() {
        expungeStaleEntries();
        return table;
    }


当我们每次要使用WeakHashMap的一些方法时、都会事先调用此方法来处理WeakHashMap、也就是删除弱引用键指向的键值对。

    3、与容量有关的内容WeakHashMap

 

    /** rehash当前WeakHashMap、此方法会在WeakHashMap容量达到阀值的时候自动调用、*/
    void resize(int newCapacity) {
        Entry[] oldTable = getTable();
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(oldTable, newTable);
        table = newTable;

        /*
         * If ignoring null elements and processing ref queue caused massive
         * shrinkage, then restore old table.  This should be rare, but avoids
         * unbounded expansion of garbage-filled tables.
         */
        if (size >= threshold / 2) {
            threshold = (int)(newCapacity * loadFactor);
        } else {
            expungeStaleEntries();
            transfer(newTable, oldTable);
            table = oldTable;
        }
    }

    /** 将原来table中所有元素转移到新的table中*/
    private void transfer(Entry[] src, Entry[] dest) {
        for (int j = 0; j < src.length; ++j) {
            Entry<K,V> e = src[j];
            src[j] = null;
            while (e != null) {
                Entry<K,V> next = e.next;
                Object key = e.get();
                if (key == null) {
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                } else {
                    int i = indexFor(e.hash, dest.length);
                    e.next = dest[i];
                    dest[i] = e;
                }
                e = next;
            }
        }
    }

        4、WeakHashMap迭代有关:从源码中可看出、WeakHashMap内部提供一个抽象类HashIterator、此类实现Iterator接口、并且提供了Iterator接口必须实现的next() hasNext() remove()方法、简化编程。WeakHashMap有三种迭代视图、一个是所有键的集合Set、一个是所有值的集合、一个是所有键值对的集合、获取三个views的流程图:

 

                a)  获取key组成的set:Iterator内部要实现next()方法、hasNext()、remove()方法使用HashIterator提供的实现。

 

java_集合体系之WeakHashMap详解、源码及示例——11_第4张图片


                b)  获取values组成的Collection:Iterator内部要实现next()方法、hasNext()、remove()方法使用HashIterator提供的实现。


java_集合体系之WeakHashMap详解、源码及示例——11_第5张图片


                c)  获取entrySet组成的Set:Iterator内部要实现next()方法、hasNext()、remove()方法使用HashIterator提供的实现。

 

java_集合体系之WeakHashMap详解、源码及示例——11_第6张图片

 

五:WeakHashMap 示例


        1、遍历方式:

a)   使用由key组成的Set:

		keySet = weakHashMap.keySet();
		Iterator<String> it = keySet.iterator();

b)  使用由value组成的Collection:

		keySet = weakHashMap.keySet();
		Iterator<String> it = keySet.iterator();

c)  使用由entry组成的Set:

		entrySet = weakHashMap.entrySet();
		Iterator<Entry<String, Integer>> it = entrySet.iterator();

        2、迭代示例:

package com.chy.collection.example;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.Map.Entry;

public class EragodicWeakHashMap {

	private static WeakHashMap<String, Integer> weakHashMap = new WeakHashMap<String, Integer>();
	private static Set<String> keySet;
	private static Collection<Integer> values;
	private static Set<Entry<String, Integer>> entrySet;
	static{
		for (int i = 0; i < 10; i++) {
			weakHashMap.put("" + i, i);
		}
	}
	
	/**
	 * iterate weakHashMap by keySet
	 */
	private static void testKeySet(){
		keySet = weakHashMap.keySet();
		Iterator<String> it = keySet.iterator();
		while(it.hasNext()){
			System.out.println("key " + it.next());
		}
		System.out.println("==================================");
	}
	
	/**
	 * iterate weakHashMap by values
	 */
	private static void testValues(){
		values = weakHashMap.values();
		Iterator<Integer> it = values.iterator();
		while(it.hasNext()){
			System.out.println("value : " + it.next());
		}
		System.out.println("==================================");
	}
	
	/**
	 * iterate weakHashMap by EntrySet
	 */
	private static void testEntrySet(){
		entrySet = weakHashMap.entrySet();
		Iterator<Entry<String, Integer>> it = entrySet.iterator();
		while(it.hasNext()){
			System.out.println("entry : " + it.next());
		}
		System.out.println("==================================");
	}
	
	/**
	 * common methods of three views
	 */
	private static void testViewsCommonMethods(){
		System.out.println("keySet size: " + keySet.size() + " values size: " + values.size() + " entrySet size: " + entrySet.size());
		System.out.println("keySet contains 1 ? " + keySet.contains("1") + " values contains 1 ? " + values.contains("1") + " entrySet contains 1 ? " + entrySet.contains("1"));
		System.out.println("keySet remove 1 ? " + keySet.remove("1") + " values remove 1 ? " + values.remove("1") + " entrySet remove 1 ? " + entrySet.remove("1"));
		keySet.clear();
		values.clear();
		entrySet.clear();
		System.out.println("keySet size: " + keySet.size() + " values size: " + values.size() + " entrySet size: " + entrySet.size());
	}
	
	public static void main(String[] args) {
		testEntrySet();
		testKeySet();
		testValues();
		testViewsCommonMethods();
	}
}

        3、API示例:


package com.chy.collection.example;

import java.util.WeakHashMap;


/**
 * WeakHashMap中所有的键如果不指向任何存在对象、则全都是弱引用对象、这样的对象会在下次调用WeakHashMap时被GC回收
 * 当一个值作为WeakHashMap的键的同时、也指向一个具体的对象、则这样的键为强引用、就暂时不会被回收。
 * 如果使用基本类型作为键、则下次调用WeakHashMap时、GC不会回收其所指定的键值对。
 */
@SuppressWarnings("unused")
public class WeakHashMapTest {
	/**
	 * 测试使用强引用作为键的WeakHashMap、
	 */
	private static void testStrongReference(){
		Key key1 = new Key("1");
		Key key2 = new Key("2");
		Key key3 = new Key("3");
		
		WeakHashMap<Key, Value> whm = new WeakHashMap<Key, Value>();
		whm.put(key1, new Value("1"));
		whm.put(key2, new Value("2"));
		whm.put(key3, new Value("3"));
		System.gc();
		System.out.println("strong reference of WeakHashMap key : " + whm);
	}
	
	/**
	 * 测试使用弱引用作为键的WeakHashMap
	 */
	private static void testWeakReference(){
		WeakHashMap<Key, Value> whm = new WeakHashMap<Key, Value>();
		whm.put(new Key("1"), new Value("1"));
		whm.put(new Key("2"), new Value("2"));
		whm.put(new Key("3"), new Value("3"));
		System.gc();
		System.out.println("weak reference of WeakHashMap key : " + whm);
	}
	
	/**
	 * 测试同时使用弱引用、强引用作为键的WeakHashMap
	 * @throws InterruptedException 
	 */
	private static void testCompoundReference(){
		 int size = 100;// 或者从命令行获得size的大小  
	        Key[] keys = new Key[size]; // 存放键对象的强引用  
	        WeakHashMap<Key, Value> whm = new WeakHashMap<Key, Value>();  
	        for (int i = 0; i < size; i++) {  
	            Key k = new Key(Integer.toString(i));  
	            Value v = new Value(Integer.toString(i));  
	            if (i % 3 == 0)  
	                keys[i] = k; // 使Key对象持有强引用   
	            whm.put(k, v); // 使Key对象持有弱引用  
	        }  
	        // 催促垃圾回收器工作  
	        System.gc();// 把CPU让给垃圾回收器线程  
	}
	/**
	 * 测试将作为键的引用从强引用变为弱引用时的WeakHashMap
	 */
	private static void testStrongToWeakReference(){
		Key key1 = new Key("1");
		Key key2 = new Key("2");
		Key key3 = new Key("3");
		
		WeakHashMap<Key, Value> whm = new WeakHashMap<Key, Value>();
		whm.put(key1, new Value("1"));
		whm.put(key2, new Value("2"));
		whm.put(key3, new Value("3"));
		
		key1 = null;
		
		//放置一个key为null的键值对
		whm.put(null, new Value("1"));
		System.gc();
		System.out.println("strong to weak reference of WeakHashMap key : " + whm);
	}
	
	
	/**
	 * 测试使用基本类型作为键的WeakHashMap
	 */
	private static void testBasicReference(){
		WeakHashMap<Integer, Value> whm = new WeakHashMap<Integer, Value>();
		whm.put(1, new Value("1"));
		whm.put(2, new Value("2"));
		whm.put(3, new Value("3"));
		System.gc();
		System.out.println("use basic as reference of WeakHashMap key : " + whm);
	}
	
	public static void main(String[] args) {
//		testStrongReference();
//		testWeakReference();
//		testCompoundReference();
//		testBasicReference();
		testStrongToWeakReference();
	}
}

class Key {  
    String id;  
  
    public Key(String id) {  
        this.id = id;  
    }  
    public String toString() {  
        return id;  
    }  
    public int hashCode() {  
        return id.hashCode();  
    }  
    public boolean equals(Object r) {  
        return (r instanceof Key) && id.equals(((Key) r).id);  
    }  
    public void finalize() {  
        System.out.println("Finalizing Key " + id);  
    }  
}  
class Value {  
    String id;  
    public Value(String id) {  
        this.id = id;  
    }  
    public String toString() {  
        return id;  
    }  
    public void finalize() {  
        System.out.println("Finalizing Value " + id);  
    }  
}  


更多内容:java_集合体系之总体目录——00



你可能感兴趣的:(源码,弱引用,HashMap,WeakHashMap,Map框架图)