• 热门专题

java集合体系之WeakHashMap详解

作者:chenghuaying  发布日期:2013-12-27 21:04:29
Tag标签:java  集合  体系  
  •  

    一:WeakHashMap结构图

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514492.jpg

    简单说明:

    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 map)


     

    2、一般方法

     

     

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

     

    四:WeakHashMap 源码分析


    说明:

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

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

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

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

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

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

    7、默认加载因子 (0.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数WeakHashMap 类的操作中,包括 getput 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 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 extends AbstractMap implements Map {
    
    	/** 初始化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 queue = new ReferenceQueue();
    
        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 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 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 e;
            while ( (e = (Entry) queue.poll()) != null) {
                int h = e.hash;
                int i = indexFor(h, table.length);
    
                Entry prev = table[i];
                Entry p = prev;
                while (p != null) {
                    Entry 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 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 getEntry(Object key) {
            Object k = maskNull(key);
            int h = HashMap.hash(k.hashCode());
            Entry[] tab = getTable();
            int index = indexFor(h, tab.length);
            Entry 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 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 e = tab[i];
            tab[i] = new Entry(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 e = src[j];
                src[j] = null;
                while (e != null) {
                    Entry 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 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 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 prev = tab[i];
            Entry e = prev;
    
            while (e != null) {
                Entry 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 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 prev = tab[i];
            Entry e = prev;
    
            while (e != null) {
                Entry 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 extends WeakReference implements Map.Entry {
            private V value;
            private final int hash;
            private Entry next;
    
            /** 创建一个实体Entry、并将Entry的key以弱引用的形式向给定的ReferenceQueue注册*/
            Entry(K key, V value, ReferenceQueue queue, int hash, Entry next) {
            	//创建引用给定对象的新的弱引用,并向给定队列注册该引用。
                super(key, queue);
                this.value = value;
                this.hash  = hash;
                this.next  = next;
            }
    
            public K getKey() {
                return WeakHashMap.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”三个迭代器
         */
        private abstract class HashIterator implements Iterator {
            int index;
            Entry entry = null;
            Entry 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 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 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 {
            public V next() {
                return nextEntry().value;
            }
        }
        // key的迭代器
        private class KeyIterator extends HashIterator {
            public K next() {
                return nextEntry().getKey();
            }
        }
    
        // Entry的迭代器
        private class EntryIterator extends HashIterator> {
            public Map.Entry next() {
                return nextEntry();
            }
        }
    
        // Views
    
        private transient Set> entrySet = null;
    
        public Set keySet() {
            Set ks = keySet;
            return (ks != null ? ks : (keySet = new KeySet()));
        }
    
        private class KeySet extends AbstractSet {
            public Iterator 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 values() {
            Collection vs = values;
            return (vs != null ?  vs : (values = new Values()));
        }
    
        private class Values extends AbstractCollection {
            public Iterator 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> entrySet() {
            Set> es = entrySet;
            return es != null ? es : (entrySet = new EntrySet());
        }
    
        private class EntrySet extends AbstractSet> {
            public Iterator> 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> deepCopy() {
    	    List> list = new ArrayList>(size());
    	    for (Map.Entry e : this)
    		list.add(new AbstractMap.SimpleEntry(e));
    	    return list;
    	}
    
            public Object[] toArray() {
                return deepCopy().toArray();
            }
    
            public  T[] toArray(T[] a) {
                return deepCopy().toArray(a);
            }
        }
    }

     

    总结 :

    1、数据结构:WeakHashMap是以哈希表的形式存储数据的、并且是通过“拉链法”解决冲突、WeakHashMap中存储的Entry实现了Map.Entry、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 extends WeakReference implements Map.Entry {
            private V value;
            private final int hash;
            private Entry next;
    
            /** 创建一个实体Entry、并将Entry的key以弱引用的形式向给定的ReferenceQueue注册*/
            Entry(K key, V value, ReferenceQueue queue, int hash, Entry next) {
            	//调用WeakReference构造方法创建引用给定对象的新的弱引用,并向给定队列注册该引用。
                super(key, queue);
                this.value = value;
                this.hash  = hash;
                this.next  = next;
            }
    
            public K getKey() {
                return WeakHashMap.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作为弱引用的实现流程图:

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514493.jpg

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

     

    2、关于WeakHashMap的使用:

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

    a) 添加:

     

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514494.jpg

     

    b) 删除:

     

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514495.jpg

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

     

     

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

     

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514496.jpg

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

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192514497.jpg

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

     

    data-cke-saved-src=http://www.it165.net/uploadfile/files/2013/1227/20131227192515498.jpg

     

    五:WeakHashMap 示例


    1、遍历方式:

    a) 使用由key组成的Set:

     

    		keySet = weakHashMap.keySet();
    		Iterator it = keySet.iterator();

     

    b) 使用由value组成的Collection:

     

    		keySet = weakHashMap.keySet();
    		Iterator it = keySet.iterator();

     

    c) 使用由entry组成的Set:

     

    		entrySet = weakHashMap.entrySet();
    		Iterator> 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 weakHashMap = new WeakHashMap();
    	private static Set keySet;
    	private static Collection values;
    	private static Set> 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 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 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> 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 whm = new WeakHashMap();
    		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 whm = new WeakHashMap();
    		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 whm = new WeakHashMap();  
    	        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 whm = new WeakHashMap();
    		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 whm = new WeakHashMap();
    		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);  
        }  
    }  

     

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规