Java tutorial
import java.util.*; import java.lang.ref.*; public class SoftHashMap extends AbstractMap implements Map { private Set entrySet = null; private Map hash; private ReferenceQueue queue = new ReferenceQueue(); static private class SoftKey extends SoftReference { private int hash; private SoftKey(Object k) { super(k); hash = k.hashCode(); } private static SoftKey create(Object k) { if (k == null) { return null; } else { return new SoftKey(k); } } private SoftKey(Object k, ReferenceQueue q) { super(k, q); hash = k.hashCode(); } private static SoftKey create(Object k, ReferenceQueue q) { if (k == null) { return null; } else { return new SoftKey(k, q); } } public boolean equals(Object o) { if (this == o) { return true; } else if (!(o instanceof SoftKey)) { return false; } Object t = this.get(); Object u = ((SoftKey) o).get(); if ((t == null) || (u == null)) { return false; } else if (t == u) { return true; } else { return t.equals(u); } } public int hashCode() { return hash; } } private void processQueue() { SoftKey sk; while ((sk = (SoftKey) queue.poll()) != null) { hash.remove(sk); } } public SoftHashMap() { hash = new HashMap(); } public SoftHashMap(Map t) { this(Math.max(2 * t.size(), 11), 0.75f); putAll(t); } public SoftHashMap(int initialCapacity) { hash = new HashMap(initialCapacity); } public SoftHashMap(int initialCapacity, float loadFactor) { hash = new HashMap(initialCapacity, loadFactor); } public int size() { return entrySet().size(); } public boolean isEmpty() { return entrySet().isEmpty(); } public boolean containsKey(Object key) { return hash.containsKey(SoftKey.create(key)); } public Object get(Object key) { return hash.get(SoftKey.create(key)); } public Object put(Object key, Object value) { processQueue(); return hash.put(SoftKey.create(key, queue), value); } public Object remove(Object key) { processQueue(); return hash.remove(SoftKey.create(key)); } public void clear() { processQueue(); hash.clear(); } private static class Entry implements Map.Entry { private Map.Entry ent; private Object key; Entry(Map.Entry ent, Object key) { this.ent = ent; this.key = key; } public Object getKey() { return key; } public Object getValue() { return ent.getValue(); } public Object setValue(Object value) { return ent.setValue(value); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } else { Map.Entry e = (Map.Entry) o; Object value = getValue(); return (key == null ? e.getKey() == null : key.equals(e.getKey())) && (value == null ? e.getValue() == null : value.equals(e.getValue())); } } public int hashCode() { Object value = getValue(); return (((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode())); } } public Set entrySet() { if (entrySet == null) { entrySet = new EntrySet(); } return entrySet; } private class EntrySet extends AbstractSet { Set set = hash.entrySet(); public Iterator iterator() { return new Iterator() { Iterator iter = set.iterator(); Entry next = null; public boolean hasNext() { while (iter.hasNext()) { Map.Entry ent = (Map.Entry) iter.next(); SoftKey sk = (SoftKey) ent.getKey(); Object k = null; if ((sk != null) && ((k = sk.get()) == null)) { /* Soft key has been cleared by GC */ continue; } next = new Entry(ent, k); return true; } return false; } public Object next() { if ((next == null) && !hasNext()) { throw new NoSuchElementException(); } Entry element = next; next = null; return element; } public void remove() { iter.remove(); } }; } public boolean isEmpty() { return !(iterator().hasNext()); } public int size() { int size = 0; for (Iterator i = iterator(); i.hasNext(); i.next(), size++) ; return size; } public boolean remove(Object o) { processQueue(); if (!(o instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) o; Object ev = e.getValue(); SoftKey sk = SoftKey.create(e.getKey()); Object hv = hash.get(sk); if ((hv == null) ? ((ev == null) && hash.containsKey(sk)) : hv.equals(ev)) { hash.remove(sk); return true; } return false; } public int hashCode() { int h = 0; for (Iterator i = set.iterator(); i.hasNext();) { Map.Entry ent = (Map.Entry) i.next(); SoftKey sk = (SoftKey) ent.getKey(); Object v; if (sk == null) { continue; } h += (sk.hashCode() ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode())); } return h; } } }