Java集合之WeakHashMap
--陆游 问渠那得清如许,为有源头活水来 --朱熹
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的遍历方式
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
// 获取key
key = (String)entry.getKey();
// 获取value
integ = (Integer)entry.getValue();
}
(2)遍历WeakHashMap的键:首先通过keySet()获取WeakHashMap的键的set集合,通过Iterator迭代器遍历集合来获得键值。
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
// 获取key
key = (String)iter.next();
// 根据key,获取value
integ = (Integer)map.get(key);
}
(3)遍历WeakHashMap的值:首先通过values()获取WeakHashMap的value集合,然后对集合进行迭代获得数据。
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext())
{
value = (Integer)iter.next();
}
WeakHashMap示例程序:
public class Hello {
public static void main(String[] args) throws Exception {
testWeakHashMapAPIs();
}
private static void testWeakHashMapAPIs()
{
// 初始化3个“弱键”
String w1 = new String("one");
String w2 = new String("two");
String w3 = new String("three");
// 新建WeakHashMap
Map wmap = new WeakHashMap();
// 添加键值对
wmap.put(w1, "w1");
wmap.put(w2, "w2");
wmap.put(w3, "w3");
// 打印出wmap
System.out.printf("\nwmap:%s\n",wmap );
// containsKey(Object key) :是否包含键key
System.out.printf("contains key two : %s\n",wmap.containsKey("two"));
System.out.printf("contains key five : %s\n",wmap.containsKey("five"));
// containsValue(Object value) :是否包含值value
)));
// remove(Object key) : 删除键key对应的键值对
wmap.remove("three");
System.out.printf("wmap: %s\n",wmap );
// ---- 测试 WeakHashMap 的自动回收特性 ----
// 将w1设置null。
// 这意味着“弱键”w1再没有被其它对象引用,调用gc时会回收WeakHashMap中与“w1”对应的键值对
w1 = null;
// 内存回收。这里,会回收WeakHashMap中与“w1”对应的键值对
System.gc();
// 遍历WeakHashMap
Iterator iter = wmap.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry en = (Map.Entry)iter.next();
System.out.printf("next : %s - %s\n",en.getKey(),en.getValue());
}
// 打印WeakHashMap的实际大小
System.out.printf(" after gc WeakHashMap size:%s\n", wmap.size());
}
}
public class WeakHashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V> {
;//默认初始大小,必须是2的次幂
;//最大值2的30次方
private static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子
Entry<K,V>[] table;
private int size;//数目
private int threshold;//阈值
private final float loadFactor;//加载因子
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();//引用队列
int modCount;//fail-fast
@SuppressWarnings("unchecked")
private Entry<K,V>[] newTable(int n) {
return (Entry<K,V>[]) new Entry<?,?>[n];
}
//构造函数
public WeakHashMap(int initialCapacity, float loadFactor) {
)
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);
;
while (capacity < initialCapacity)
capacity <<= ;
table = newTable(capacity);
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
}
//初始值的构造函数
public WeakHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
//构造函数
public WeakHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public WeakHashMap(Map<? extends K, ? extends V> m) {
,
DEFAULT_INITIAL_CAPACITY),
DEFAULT_LOAD_FACTOR);
putAll(m);
}
// internal utilities
/**
* Value representing null keys inside tables.
*/
private static final Object NULL_KEY = new Object();
/**
* Use NULL_KEY for key if it is null.
*/
private static Object maskNull(Object key) {
return (key == null) ? NULL_KEY : key;
}
/**
* Returns internal representation of null key back to caller as null.
*/
static Object unmaskNull(Object key) {
return (key == NULL_KEY) ? null : key;
}
/**
* Checks for equality of non-null reference x and possibly-null y. By
* default uses Object.equals.
*/
private static boolean eq(Object x, Object y) {
return x == y || x.equals(y);
}
/**
* Retrieve object hash code and applies a supplemental hash function to the
* result hash, which defends against poor quality hash functions. This is
* critical because HashMap uses power-of-two length hash tables, that
* otherwise encounter collisions for hashCodes that do not differ
* in lower bits.
*/
//计算k的hash
final int hash(Object k) {
int h = k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
) ^ (h >>> );
) ^ (h >>> );
}
/**
* Returns index for hash code h.
*/
private static int indexFor(int h, int length) {
);
}
/**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
/**
* Returns the table after first expunging stale entries.
*/
private Entry<K,V>[] getTable() {
expungeStaleEntries();
return table;
}
/**
* Returns the number of key-value mappings in this map.
* This result is a snapshot, and may not reflect unprocessed
* entries that will be removed before next attempted access
* because they are no longer referenced.
*/
//返回数目
public int size() {
)
;
expungeStaleEntries();
return size;
}
/**
* Returns <tt>true</tt> if this map contains no key-value mappings.
* This result is a snapshot, and may not reflect unprocessed
* entries that will be removed before next attempted access
* because they are no longer referenced.
*/
//判断是否为空
public boolean isEmpty() {
;
}
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
*
* <p>More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (key==null ? k==null :
* key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
*
* <p>A return value of {@code null} does not <i>necessarily</i>
* indicate that the map contains no mapping for the key; it's also
* possible that the map explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
*
* @see #put(Object, Object)
*/
//通过key获得value
public V get(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] 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;
}
/**
* Returns <tt>true</tt> if this map contains a mapping for the
* specified key.
*
* @param key The key whose presence in this map is to be tested
* @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
* <tt>false</tt> otherwise
*/
//判断是否包含某个key
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
/**
* Returns the entry associated with the specified key in this map.
* Returns null if the map contains no mapping for this key.
*/
//通过key获得entry
Entry<K,V> getEntry(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] 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;
}
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for this key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
//插入key和value
public V put(K key, V value) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable();
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
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, value, queue, h, e);
if (++size >= threshold)
resize(tab.);
return null;
}
/**
* Rehashes the contents of this map into a new array with a
* larger capacity. This method is called automatically when the
* number of keys in this map reaches its threshold.
*
* If current capacity is MAXIMUM_CAPACITY, this method does not
* resize the map, but sets threshold to Integer.MAX_VALUE.
* This has the effect of preventing future calls.
*
* @param newCapacity the new capacity, MUST be a power of two;
* must be greater than current capacity unless current
* capacity is MAXIMUM_CAPACITY (in which case value
* is irrelevant).
*/
//跳转大小
void resize(int newCapacity) {
Entry<K,V>[] oldTable = getTable();
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry<K,V>[] newTable = newTable(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.
*/
) {
threshold = (int)(newCapacity * loadFactor);
} else {
expungeStaleEntries();
transfer(newTable, oldTable);
table = oldTable;
}
}
/** Transfers all entries from src to dest tables */
private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
; 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;
}
}
}
/**
* Copies all of the mappings from the specified map to this map.
* These mappings will replace any mappings that this map had for any
* of the keys currently in the specified map.
*
* @param m mappings to be stored in this map.
* @throws NullPointerException if the specified map is null.
*/
public void putAll(Map<? extends K, ? extends V> m) {
int numKeysToBeAdded = m.size();
)
return;
/*
* Expand the map if the map if the number of mappings to be added
* is greater than or equal to threshold. This is conservative; the
* obvious condition is (m.size() + size) >= threshold, but this
* condition could result in a map with twice the appropriate capacity,
* if the keys to be added overlap with the keys already in this map.
* By using the conservative calculation, we subject ourself
* to at most one extra resize.
*/
if (numKeysToBeAdded > threshold) {
);
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= ;
if (newCapacity > table.length)
resize(newCapacity);
}
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
/**
* Removes the mapping for a key from this weak hash map if it is present.
* More formally, if this map contains a mapping from key <tt>k</tt> to
* value <tt>v</tt> such that <code>(key==null ? k==null :
* key.equals(k))</code>, that mapping is removed. (The map can contain
* at most one such mapping.)
*
* <p>Returns the value to which this map previously associated the key,
* or <tt>null</tt> if the map contained no mapping for the key. A
* return value of <tt>null</tt> does not <i>necessarily</i> indicate
* that the map contained no mapping for the key; it's also possible
* that the map explicitly mapped the key to <tt>null</tt>.
*
* <p>The map will not contain a mapping for the specified key once the
* call returns.
*
* @param key key whose mapping is to be removed from the map
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>
*/
//根据key删除
public V remove(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] 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 */
boolean removeMapping(Object o) {
if (!(o instanceof Map.Entry))
return false;
Entry<K,V>[] tab = getTable();
Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
Object k = maskNull(entry.getKey());
int h = hash(k);
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 true;
}
prev = e;
e = next;
}
return false;
}
/**
* Removes all of the mappings from this map.
* The map will be empty after this call returns.
*/
//清空
public void clear() {
// clear out ref queue. We don't need to expunge entries
// since table is getting cleared.
while (queue.poll() != null)
;
modCount++;
Arrays.fill(table, null);
;
// 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)
;
}
/**
* Returns <tt>true</tt> if this map maps one or more keys to the
* specified value.
*
* @param value value whose presence in this map is to be tested
* @return <tt>true</tt> if this map maps one or more keys to the
* specified value
*/
//判断是否包含某个值
public boolean containsValue(Object value) {
if (value==null)
return containsNullValue();
Entry<K,V>[] tab = getTable();
;)
for (Entry<K,V> e = tab[i]; e != null; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
/**
* Special-case code for containsValue with null argument
*/
//判断是否有空值
private boolean containsNullValue() {
Entry<K,V>[] tab = getTable();
;)
for (Entry<K,V> e = tab[i]; e != null; e = e.next)
if (e.value==null)
return true;
return false;
}
/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
//entry继承了虚引用
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
@SuppressWarnings("unchecked")
public K getKey() {
return (K) 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;
K k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
V v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public int hashCode() {
K k = getKey();
V v = getValue();
return Objects.hashCode(k) ^ Objects.hashCode(v);
}
public String toString() {
return getKey() + "=" + getValue();
}
}
private abstract class HashIterator<T> implements Iterator<T> {
private int index;
private Entry<K,V> entry;
private Entry<K,V> lastReturned;
private int expectedModCount = modCount;
/**
* Strong reference needed to avoid disappearance of key
* between hasNext and next
*/
private Object nextKey;
/**
* Strong reference needed to avoid disappearance of key
* between nextEntry() and any use of the entry
*/
private Object currentKey;
HashIterator() {
index = isEmpty() ? 0 : table.length;
}
public boolean hasNext() {
Entry<K,V>[] t = table;
while (nextKey == null) {
Entry<K,V> e = entry;
int i = index;
)
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;
}
/** The common parts of next() across different types of iterators */
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;
}
}
private class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
private class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
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;
/**
* Returns a {@link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own <tt>remove</tt> operation), the results of
* the iteration are undefined. The set supports element removal,
* which removes the corresponding mapping from the map, via the
* <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
* operations.
*/
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 Spliterator<K> spliterator() {
);
}
}
/**
* Returns a {@link Collection} view of the values contained in this map.
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. If the map is
* modified while an iteration over the collection is in progress
* (except through the iterator's own <tt>remove</tt> operation),
* the results of the iteration are undefined. The collection
* supports element removal, which removes the corresponding
* mapping from the map, via the <tt>Iterator.remove</tt>,
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
* support the <tt>add</tt> or <tt>addAll</tt> operations.
*/
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 Spliterator<V> spliterator() {
);
}
}
/**
* Returns a {@link Set} view of the mappings contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own <tt>remove</tt> operation, or through the
* <tt>setValue</tt> operation on a map entry returned by the
* iterator) the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
* mapping from the map, via the <tt>Iterator.remove</tt>,
* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
* <tt>clear</tt> operations. It does not support the
* <tt>add</tt> or <tt>addAll</tt> operations.
*/
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;
Entry<K,V> candidate = getEntry(e.getKey());
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o);
}
public int size() {
return WeakHashMap.this.size();
}
public void clear() {
WeakHashMap.this.clear();
}
private List<Map.Entry<K,V>> deepCopy() {
List<Map.Entry<K,V>> list = new ArrayList<>(size());
for (Map.Entry<K,V> e : this)
list.add(new AbstractMap.SimpleEntry<>(e));
return list;
}
public Object[] toArray() {
return deepCopy().toArray();
}
public <T> T[] toArray(T[] a) {
return deepCopy().toArray(a);
}
public Spliterator<Map.Entry<K,V>> spliterator() {
);
}
}
@SuppressWarnings("unchecked")
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
int expectedModCount = modCount;
Entry<K, V>[] tab = getTable();
for (Entry<K, V> entry : tab) {
while (entry != null) {
Object key = entry.get();
if (key != null) {
action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
}
entry = entry.next;
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
}
@SuppressWarnings("unchecked")
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
int expectedModCount = modCount;
Entry<K, V>[] tab = getTable();;
for (Entry<K, V> entry : tab) {
while (entry != null) {
Object key = entry.get();
if (key != null) {
entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
}
entry = entry.next;
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
}
/**
* Similar form as other hash Spliterators, but skips dead
* elements.
*/
static class WeakHashMapSpliterator<K,V> {
final WeakHashMap<K,V> map;
WeakHashMap.Entry<K,V> current; // current node
int index; // current index, modified on advance/split
int fence; // -1 until first use; then one past last index
int est; // size estimate
int expectedModCount; // for comodification checks
WeakHashMapSpliterator(WeakHashMap<K,V> m, int origin,
int fence, int est,
int expectedModCount) {
this.map = m;
this.index = origin;
this.fence = fence;
this.est = est;
this.expectedModCount = expectedModCount;
}
final int getFence() { // initialize fence and size on first use
int hi;
) {
WeakHashMap<K,V> m = map;
est = m.size();
expectedModCount = m.modCount;
hi = fence = m.table.length;
}
return hi;
}
public final long estimateSize() {
getFence(); // force init
return (long) est;
}
}
static final class KeySpliterator<K,V>
extends WeakHashMapSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public KeySpliterator<K,V> trySplit() {
;
return (lo >= mid) ? null :
,
expectedModCount);
}
public void forEachRemaining(Consumer<? super K> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
WeakHashMap<K,V> m = map;
WeakHashMap.Entry<K,V>[] tab = m.table;
) {
mc = expectedModCount = m.modCount;
hi = fence = tab.length;
}
else
mc = expectedModCount;
if (tab.length >= hi && (i = index) >= 0 &&
(i < (index = hi) || current != null)) {
WeakHashMap.Entry<K,V> p = current;
current = null; // exhaust
do {
if (p == null)
p = tab[i++];
else {
Object x = p.get();
p = p.next;
if (x != null) {
@SuppressWarnings("unchecked") K k =
(K) WeakHashMap.unmaskNull(x);
action.accept(k);
}
}
} while (p != null || i < hi);
}
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer<? super K> action) {
int hi;
if (action == null)
throw new NullPointerException();
WeakHashMap.Entry<K,V>[] tab = map.table;
) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
Object x = current.get();
current = current.next;
if (x != null) {
@SuppressWarnings("unchecked") K k =
(K) WeakHashMap.unmaskNull(x);
action.accept(k);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
}
return false;
}
public int characteristics() {
return Spliterator.DISTINCT;
}
}
static final class ValueSpliterator<K,V>
extends WeakHashMapSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public ValueSpliterator<K,V> trySplit() {
;
return (lo >= mid) ? null :
,
expectedModCount);
}
public void forEachRemaining(Consumer<? super V> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
WeakHashMap<K,V> m = map;
WeakHashMap.Entry<K,V>[] tab = m.table;
) {
mc = expectedModCount = m.modCount;
hi = fence = tab.length;
}
else
mc = expectedModCount;
if (tab.length >= hi && (i = index) >= 0 &&
(i < (index = hi) || current != null)) {
WeakHashMap.Entry<K,V> p = current;
current = null; // exhaust
do {
if (p == null)
p = tab[i++];
else {
Object x = p.get();
V v = p.value;
p = p.next;
if (x != null)
action.accept(v);
}
} while (p != null || i < hi);
}
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer<? super V> action) {
int hi;
if (action == null)
throw new NullPointerException();
WeakHashMap.Entry<K,V>[] tab = map.table;
) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
Object x = current.get();
V v = current.value;
current = current.next;
if (x != null) {
action.accept(v);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
}
return false;
}
public int characteristics() {
;
}
}
static final class EntrySpliterator<K,V>
extends WeakHashMapSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public EntrySpliterator<K,V> trySplit() {
;
return (lo >= mid) ? null :
,
expectedModCount);
}
public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
WeakHashMap<K,V> m = map;
WeakHashMap.Entry<K,V>[] tab = m.table;
) {
mc = expectedModCount = m.modCount;
hi = fence = tab.length;
}
else
mc = expectedModCount;
if (tab.length >= hi && (i = index) >= 0 &&
(i < (index = hi) || current != null)) {
WeakHashMap.Entry<K,V> p = current;
current = null; // exhaust
do {
if (p == null)
p = tab[i++];
else {
Object x = p.get();
V v = p.value;
p = p.next;
if (x != null) {
@SuppressWarnings("unchecked") K k =
(K) WeakHashMap.unmaskNull(x);
action.accept
(new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
}
}
} while (p != null || i < hi);
}
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
int hi;
if (action == null)
throw new NullPointerException();
WeakHashMap.Entry<K,V>[] tab = map.table;
) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
Object x = current.get();
V v = current.value;
current = current.next;
if (x != null) {
@SuppressWarnings("unchecked") K k =
(K) WeakHashMap.unmaskNull(x);
action.accept
(new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
}
return false;
}
public int characteristics() {
return Spliterator.DISTINCT;
}
}
}
Java集合之WeakHashMap的更多相关文章
- 死磕 java集合之WeakHashMap源码分析
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 WeakHashMap是一种弱引用map,内部的key会存储为弱引用,当jvm gc的时 ...
- 死磕 java集合之终结篇
概览 我们先来看一看java中所有集合的类关系图. 这里面的类太多了,请放大看,如果放大还看不清,请再放大看,如果还是看不清,请放弃. 我们下面主要分成五个部分来逐个击破. List List中的元素 ...
- Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)
概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转 ...
- Java 集合系列 13 WeakHashMap
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合 持有引用 & WeakHashMap
Java 集合 持有引用 & WeakHashMap @author ixenos 摘要:强引用.弱引用.WeakHashMap动态回收步骤 Reference引用对象 可获得的(reacha ...
- Java集合框架List,Map,Set等全面介绍
Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I] +--java.util.ArrayList [C] +- ...
- Java 集合框架
Java集合框架大致可以分为五个部分:List列表,Set集合.Map映射.迭代器.工具类 List 接口通常表示一个列表(数组.队列.链表 栈),其中的元素 可以重复 的是:ArrayList 和L ...
- Java 集合系列目录(Category)
下面是最近总结的Java集合(JDK1.6.0_45)相关文章的目录. 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系 ...
- Java集合源码分析(一)
Java集合工具包位于Java.util包下,包含了很多常用的数据结构,如数组.链表.栈.队列.集合.哈希表等.学习Java集合框架下大致可以分为如下五个部分:List列表.Set集合.Map映射.迭 ...
随机推荐
- “ML学分计划”说明书
计划的由来 我们是一群对机器学习感兴趣的小伙伴,对于神奇的机器学习经常有"一探究竟"的冲动,却因为孤身一人学习的寂寞.亦或繁忙考试工作之余的小小拖延症,而没有持续这份对知识的渴求和 ...
- linux下内存的统计和内存泄露类问题的定位
在产品的开发中,通过对当前系统消耗内存总量的统计,可以对产品所需内存总量进行精确的评估,从而选择合适的内存芯片与大小,降低产品的成本.在遇到内存泄露类问题时,经常会对此束手无策,本文通过对proc下进 ...
- [code segments] OpenCV3.0 SVM with C++ interface
talk is cheap, show you the code: /***************************************************************** ...
- Android TV开发总结(一)构建一个TV app前要知道的事儿
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52792562 前言:近年来,智能 ...
- Spark-1.6.0之Application运行信息记录器JobProgressListener
JobProgressListener类是Spark的ListenerBus中一个很重要的监听器,可以用于记录Spark任务的Job和Stage等信息,比如在Spark UI页面上Job和Stage运 ...
- 如何正确使用const、static、extern
转自:http://www.jianshu.com/p/2fd58ed2cf55 前言 本篇文章主要介绍在开发中怎么使用const.static.extern关键字. 一.const 与宏的区别: c ...
- EBS销售订单挑库发放处理程序
来自:http://blog.csdn.net/cunxiyuan108/article/details/6014769 在EBS实施中,经常遇到从外部传进来一个被登记的销售订单,需要通过程序进行销售 ...
- [error]error while loading shared libraries: libpcre.so.1 解决
nginx 安装好之后,启动的时候报错 [root@localhost nginx-1.6.2]# /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin ...
- SQL语句容易出现错误的地方-连载
1.语言问题 修改语言注册表\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432\ORACLE\KEY_DevSuitHome1中的NLS_LANG修改为AMERICAN_AMER ...
- Swift变量名的一种玩法
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 是的,Swift的变量名可以用任何合法的Unicode字符,这 ...