您的位置:首页 > 编程语言 > Java开发

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

2013-12-27 14:58 761 查看

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

 

一:WeakHashMap结构图

                


简单说明:

        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)  添加:

 

                


 

                b)  删除:

                 


                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提供的实现。

 



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



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

 



 

五: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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息