* The null element is supported. * This class has performance characteristics similar to those of the * HashSet class, and has the same efficiency parameters of * initial capacity and load factor. *
* Like most collection classes, this class is not synchronized. * A synchronized WeakHashSet may be constructed using the * Collections.synchronizedSet method. *
* This class is intended primarily for use with objects whose * equals methods test for object identity using the * == 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 WeakHashSet at some later * time and be surprised that its entry has been removed. * This class will work perfectly well with objects whose equals * methods are not based upon object identity, such as String * instances. * With such recreatable objects however, the automatic removal of * WeakHashSet elements that have been discarded may prove to be * confusing. *
* The behavior of the WeakHashSet class depends in part upon the * actions of the garbage collector, so several familiar (though not required) * Set invariants do not hold for this class. * Because the garbage collector may discard elements at any time, a * WeakHashSet may behave as though an unknown thread is silently * removing elements. * In particular, even if you synchronize on a WeakHashSet instance and * invoke none of its mutator methods, it is possible for the size * method to return smaller values over time, for the isEmpty method to * return false and then true, for the contains * method to return true and later false for a given object, * for the add method to return true and the remove * method to return false 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. *
* Each element in a WeakHashSet 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. *
* The iterators returned by this class are fail-fast: if the set is * structurally modified at any time after the iterator is created, in any way * except through the iterator's own remove or add methods, * the iterator will throw a ConcurrentModificationException. * 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. *
* 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 ConcurrentModificationException on a
* best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness: the fail-fast behavior of iterators
* should be used only to detect bugs.
*
*
* @author Mike Martin (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 WeakHashMap 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 WeakHashMap 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 WeakHashMap 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 WeakHashMap instance has
* the specified initial capacity and default load factor, which is
* 0.75.
*
* @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 true
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 true
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 true
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 true
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();
}
}