一、前言
关于apache的源码包commons-logging-optional.jar.zip中提供了org.apache.commons.logging.impl.WeakHashtable弱引用自定义哈希表,其继承Hashtable并对保存对象的引用关系使用了WeakReference,对于大数据内存优化等场景提供更好的内存利用率。
二、源码说明
package org.apache.commons.logging.impl;@b@@b@import java.lang.ref.ReferenceQueue;@b@import java.lang.ref.WeakReference;@b@import java.util.Collection;@b@import java.util.Enumeration;@b@import java.util.HashSet;@b@import java.util.Hashtable;@b@import java.util.Iterator;@b@import java.util.Map;@b@import java.util.Map.Entry;@b@import java.util.Set;@b@@b@public final class WeakHashtable extends Hashtable@b@{@b@ private static final int MAX_CHANGES_BEFORE_PURGE = 100;@b@ private static final int PARTIAL_PURGE_COUNT = 10;@b@ private ReferenceQueue queue = new ReferenceQueue();@b@ private int changeCount = 0;@b@@b@ public boolean containsKey(Object key)@b@ {@b@ Referenced referenced = new Referenced(key, null);@b@ return super.containsKey(referenced);@b@ }@b@@b@ public Enumeration elements()@b@ {@b@ purge();@b@ return super.elements();@b@ }@b@@b@ public Set entrySet()@b@ {@b@ purge();@b@ Set referencedEntries = super.entrySet();@b@ Set unreferencedEntries = new HashSet();@b@ for (Iterator it = referencedEntries.iterator(); it.hasNext(); ) {@b@ Map.Entry entry = (Map.Entry)it.next();@b@ Referenced referencedKey = (Referenced)entry.getKey();@b@ Object key = Referenced.access$100(referencedKey);@b@ Object value = entry.getValue();@b@ if (key == null) break label94;@b@ Entry dereferencedEntry = new Entry(key, value, null);@b@ label94: unreferencedEntries.add(dereferencedEntry);@b@ }@b@@b@ return unreferencedEntries;@b@ }@b@@b@ public Object get(Object key)@b@ {@b@ Referenced referenceKey = new Referenced(key, null);@b@ return super.get(referenceKey);@b@ }@b@@b@ public Enumeration keys()@b@ {@b@ purge();@b@ Enumeration enumer = super.keys();@b@ return new Enumeration(this, enumer) { private final Enumeration val$enumer;@b@ private final WeakHashtable this$0;@b@@b@ public boolean hasMoreElements() { return this.val$enumer.hasMoreElements(); }@b@@b@ public Object nextElement() {@b@ WeakHashtable.Referenced nextReference = (WeakHashtable.Referenced)this.val$enumer.nextElement();@b@ return WeakHashtable.Referenced.access$100(nextReference);@b@ }@b@ };@b@ }@b@@b@ public Set keySet()@b@ {@b@ purge();@b@ Set referencedKeys = super.keySet();@b@ Set unreferencedKeys = new HashSet();@b@ for (Iterator it = referencedKeys.iterator(); it.hasNext(); ) {@b@ Referenced referenceKey = (Referenced)it.next();@b@ Object keyValue = Referenced.access$100(referenceKey);@b@ if (keyValue == null) break label59;@b@ label59: unreferencedKeys.add(keyValue);@b@ }@b@@b@ return unreferencedKeys;@b@ }@b@@b@ public Object put(Object key, Object value)@b@ {@b@ if (key == null)@b@ throw new NullPointerException("Null keys are not allowed");@b@@b@ if (value == null) {@b@ throw new NullPointerException("Null values are not allowed");@b@ }@b@@b@ if (this.changeCount++ > 100) {@b@ purge();@b@ this.changeCount = 0;@b@ }@b@ else if (this.changeCount % 10 == 0) {@b@ purgeOne();@b@ }@b@@b@ Object result = null;@b@ Referenced keyRef = new Referenced(key, this.queue, null);@b@ return super.put(keyRef, value);@b@ }@b@@b@ public void putAll(Map t)@b@ {@b@ if (t != null) {@b@ Set entrySet = t.entrySet();@b@ for (Iterator it = entrySet.iterator(); it.hasNext(); ) {@b@ Map.Entry entry = (Map.Entry)it.next();@b@ put(entry.getKey(), entry.getValue());@b@ }@b@ }@b@ }@b@@b@ public Collection values()@b@ {@b@ purge();@b@ return super.values();@b@ }@b@@b@ public Object remove(Object key)@b@ {@b@ if (this.changeCount++ > 100) {@b@ purge();@b@ this.changeCount = 0;@b@ }@b@ else if (this.changeCount % 10 == 0) {@b@ purgeOne();@b@ }@b@ return super.remove(new Referenced(key, null));@b@ }@b@@b@ public boolean isEmpty()@b@ {@b@ purge();@b@ return super.isEmpty();@b@ }@b@@b@ public int size()@b@ {@b@ purge();@b@ return super.size();@b@ }@b@@b@ public String toString()@b@ {@b@ purge();@b@ return super.toString();@b@ }@b@@b@ protected void rehash()@b@ {@b@ purge();@b@ super.rehash();@b@ }@b@@b@ private void purge()@b@ {@b@ synchronized (this.queue)@b@ {@b@ WeakKey key;@b@ while ((key = (WeakKey)this.queue.poll()) != null) {@b@ WeakKey localWeakKey1;@b@ super.remove(WeakKey.access$400(localWeakKey1));@b@ }@b@ }@b@ }@b@@b@ private void purgeOne()@b@ {@b@ synchronized (this.queue) {@b@ WeakKey key = (WeakKey)this.queue.poll();@b@ if (key != null)@b@ super.remove(WeakKey.access$400(key));@b@ }@b@ }@b@@b@ private static final class WeakKey extends WeakReference@b@ {@b@ private final WeakHashtable.Referenced referenced;@b@@b@ private WeakKey(Object key, ReferenceQueue queue, WeakHashtable.Referenced referenced)@b@ {@b@ super(key, queue);@b@ this.referenced = referenced;@b@ }@b@@b@ private WeakHashtable.Referenced getReferenced() {@b@ return this.referenced;@b@ }@b@@b@ static WeakHashtable.Referenced access$400(WeakKey x0)@b@ {@b@ return x0.getReferenced(); } @b@ WeakKey(Object x0, ReferenceQueue x1, WeakHashtable.Referenced x2, WeakHashtable.1 x3) { this(x0, x1, x2);@b@ }@b@ }@b@@b@ private static final class Referenced@b@ {@b@ private final WeakReference reference;@b@ private final int hashCode;@b@@b@ private Referenced(Object referant)@b@ {@b@ this.reference = new WeakReference(referant);@b@@b@ this.hashCode = referant.hashCode();@b@ }@b@@b@ private Referenced(Object key, ReferenceQueue queue)@b@ {@b@ this.reference = new WeakHashtable.WeakKey(key, queue, this, null);@b@@b@ this.hashCode = key.hashCode();@b@ }@b@@b@ public int hashCode()@b@ {@b@ return this.hashCode;@b@ }@b@@b@ private Object getValue() {@b@ return this.reference.get();@b@ }@b@@b@ public boolean equals(Object o) {@b@ boolean result = false;@b@ if (o instanceof Referenced) {@b@ Referenced otherKey = (Referenced)o;@b@ Object thisKeyValue = getValue();@b@ Object otherKeyValue = otherKey.getValue();@b@ if (thisKeyValue == null) {@b@ result = otherKeyValue == null;@b@@b@ if (result == true) {@b@ result = hashCode() == otherKey.hashCode();@b@ }@b@@b@ }@b@ else@b@ {@b@ result = thisKeyValue.equals(otherKeyValue);@b@ }@b@ }@b@ return result;@b@ }@b@@b@ Referenced(Object x0, WeakHashtable.1 x1)@b@ {@b@ this(x0); } @b@ static Object access$100(Referenced x0) { return x0.getValue(); } @b@ Referenced(Object x0, ReferenceQueue x1, WeakHashtable.1 x2) { this(x0, x1);@b@ }@b@ }@b@@b@ private static final class Entry@b@ implements Map.Entry@b@ {@b@ private final Object key;@b@ private final Object value;@b@@b@ private Entry(Object key, Object value)@b@ {@b@ this.key = key;@b@ this.value = value;@b@ }@b@@b@ public boolean equals(Object o) {@b@ boolean result = false;@b@ if ((o != null) && (o instanceof Map.Entry)) {@b@ Map.Entry entry = (Map.Entry)o;@b@ if (getKey() == null) if (entry.getKey() != null) break label92; @b@ else if (!(getKey().equals(entry.getKey()))) break label92; @b@ if (getValue() == null) if (entry.getValue() != null) break label92; @b@ label92: result = getValue().equals(entry.getValue());@b@ }@b@@b@ return result;@b@ }@b@@b@ public int hashCode()@b@ {@b@ return (((getKey() == null) ? 0 : getKey().hashCode()) ^ ((getValue() == null) ? 0 : getValue().hashCode()));@b@ }@b@@b@ public Object setValue(Object value)@b@ {@b@ throw new UnsupportedOperationException("Entry.setValue is not supported.");@b@ }@b@@b@ public Object getValue() {@b@ return this.value;@b@ }@b@@b@ public Object getKey() {@b@ return this.key;@b@ }@b@@b@ Entry(Object x0, Object x1, WeakHashtable.1 x2)@b@ {@b@ this(x0, x1);@b@ }@b@ }@b@}