Java tutorial
/* * Copyright 2004 (C) TJDO. * All rights reserved. * * This software is distributed under the terms of the TJDO License version 1.0. * See the terms of the TJDO License in the documentation provided with this software. * * $Id: WeakHashSet.java,v 1.1 2004/08/09 23:53:35 jackknifebarber Exp $ */ import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.WeakHashMap; /** * A <tt>Set</tt> implementation with <em>weak elements</em>. * This class implements the <tt>Set</tt> interface, backed by a hash table with * weak keys (actually a <tt>WeakHashMap</tt> instance). * An element in a <tt>WeakHashSet</tt> will automatically be removed when it * is no longer in ordinary use. * More precisely, the presence of an element will not prevent it from being * discarded by the garbage collector, that is, made finalizable, finalized, * and then reclaimed. * When a element has been discarded it is effectively removed from the set, * so this class behaves somewhat differently than other <tt>Set</tt> * implementations. * <p> * The null element is supported. * This class has performance characteristics similar to those of the * <tt>HashSet</tt> class, and has the same efficiency parameters of * <em>initial capacity</em> and <em>load factor</em>. * <p> * Like most collection classes, this class is not synchronized. * A synchronized <tt>WeakHashSet</tt> may be constructed using the * <tt>Collections.synchronizedSet</tt> method. * <p> * This class is intended primarily for use with objects whose * <tt>equals</tt> methods test for object identity using the * <tt>==</tt> operator. * Once such an object is discarded it can never be recreated, so it is * impossible to do a lookup of that key in a <tt>WeakHashSet</tt> at some later * time and be surprised that its entry has been removed. * This class will work perfectly well with objects whose <tt>equals</tt> * methods are not based upon object identity, such as <tt>String</tt> * instances. * With such recreatable objects however, the automatic removal of * <tt>WeakHashSet</tt> elements that have been discarded may prove to be * confusing. * <p> * The behavior of the <tt>WeakHashSet</tt> class depends in part upon the * actions of the garbage collector, so several familiar (though not required) * <tt>Set</tt> invariants do not hold for this class. * Because the garbage collector may discard elements at any time, a * <tt>WeakHashSet</tt> may behave as though an unknown thread is silently * removing elements. * In particular, even if you synchronize on a <tt>WeakHashSet</tt> instance and * invoke none of its mutator methods, it is possible for the <tt>size</tt> * method to return smaller values over time, for the <tt>isEmpty</tt> method to * return <tt>false</tt> and then <tt>true</tt>, for the <tt>contains</tt> * method to return <tt>true</tt> and later <tt>false</tt> for a given object, * for the <tt>add</tt> method to return <tt>true</tt> and the <tt>remove</tt> * method to return <tt>false</tt> for an element that previously appeared to be * in the set, and for successive examinations of the set to yield successively * smaller numbers of elements. * <p> * Each element in a <tt>WeakHashSet</tt> is stored indirectly as the referent * of a weak reference. * Therefore an element will automatically be removed only after the weak * references to it, both inside and outside of the set, have been cleared by * the garbage collector. * <p> * The iterators returned by this class are <i>fail-fast</i>: if the set is * structurally modified at any time after the iterator is created, in any way * except through the iterator's own <tt>remove</tt> or <tt>add</tt> methods, * the iterator will throw a <tt>ConcurrentModificationException</tt>. * Thus, in the face of concurrent modification, the iterator fails quickly and * cleanly, rather than risking arbitrary, non-deterministic behavior at an * undetermined time in the future. * <p> * Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. * Fail-fast iterators throw <tt>ConcurrentModificationException</tt> on a * best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: <i>the fail-fast behavior of iterators * should be used only to detect bugs.</i> * * * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a> (borrowing * liberally from java.util.HashSet) * @version $Revision: 1.1 $ */ public class WeakHashSet extends AbstractSet implements Set { /* Dummy value to associate with an Object in the backing Map. */ private static final Object PRESENT = new Object(); private final WeakHashMap map; /** * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */ public WeakHashSet() { map = new WeakHashMap(); } /** * Constructs a new set containing the elements in the specified * collection. The <tt>WeakHashMap</tt> is created with default load factor * (0.75) and an initial capacity sufficient to contain the elements in * the specified collection. * * @param c the collection whose elements are to be placed into this set. * @throws NullPointerException if the specified collection is null. */ public WeakHashSet(Collection c) { map = new WeakHashMap(Math.max((int) (c.size() / .75f) + 1, 16)); addAll(c); } /** * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has * the specified initial capacity and the specified load factor. * * @param initialCapacity the initial capacity of the hash map. * @param loadFactor the load factor of the hash map. * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive. */ public WeakHashSet(int initialCapacity, float loadFactor) { map = new WeakHashMap(initialCapacity, loadFactor); } /** * Constructs a new, empty set; the backing <tt>WeakHashMap</tt> instance has * the specified initial capacity and default load factor, which is * <tt>0.75</tt>. * * @param initialCapacity the initial capacity of the hash table. * @throws IllegalArgumentException if the initial capacity is less * than zero. */ public WeakHashSet(int initialCapacity) { map = new WeakHashMap(initialCapacity); } /** * Returns an iterator over the elements in this set. The elements * are returned in no particular order. * * @return an Iterator over the elements in this set. * @see "java.util.ConcurrentModificationException" */ public Iterator iterator() { return map.keySet().iterator(); } /** * Returns the number of elements in this set (its cardinality). * * @return the number of elements. */ public int size() { return map.size(); } /** * Indicates whether the set is empty. * * @return <code>true</code> if the set contains no elements. */ public boolean isEmpty() { return map.isEmpty(); } /** * Indicates whether the set contains the specified element. * * @param o the element to specify. * @return <code>true</code> if the set contains the specified element. */ public boolean contains(Object o) { return map.containsKey(o); } /** * Adds the specified element to the set if it is not already * present. * * @param o the element to be added. * @return <code>true</code> if the set did not already contain the specified * element. */ public boolean add(Object o) { return map.put(o, PRESENT) == null; } /** * Removes the specified element from the set if it is present. * * @param o the element to be removed. * @return <code>true</code> if the set contained the specified element. */ public boolean remove(Object o) { return map.remove(o) == PRESENT; } /** * Removes all of the elements from the set. */ public void clear() { map.clear(); } }