1. /*
  2. * @(#)HashSet.java 1.15 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util;
  8. /**
  9. * This class implements the <tt>Set</tt> interface, backed by a hash table
  10. * (actually a <tt>HashMap</tt> instance). It makes no guarantees as to the
  11. * iteration order of the set; in particular, it does not guarantee that the
  12. * order will remain constant over time. This class permits the <tt>null</tt>
  13. * element.<p>
  14. *
  15. * This class offers constant time performance for the basic operations
  16. * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),
  17. * assuming the hash function disperses the elements properly among the
  18. * buckets. Iterating over this set requires time proportional to the sum of
  19. * the <tt>HashSet</tt> instance's size (the number of elements) plus the
  20. * "capacity" of the backing <tt>HashMap</tt> instance (the number of
  21. * buckets). Thus, it's very important not to set the intial capacity too
  22. * high (or the load factor too low) if iteration performance is important.<p>
  23. *
  24. * <b>Note that this implementation is not synchronized.</b> If multiple
  25. * threads access a set concurrently, and at least one of the threads modifies
  26. * the set, it <i>must</i> be synchronized externally. This is typically
  27. * accomplished by synchronizing on some object that naturally encapsulates
  28. * the set. If no such object exists, the set should be "wrapped" using the
  29. * <tt>Collections.synchronizedSet</tt> method. This is best done at creation
  30. * time, to prevent accidental unsynchronized access to the <tt>HashSet</tt>
  31. * instance:
  32. *
  33. * <pre>
  34. * Set s = Collections.synchronizedSet(new HashSet(...));
  35. * </pre><p>
  36. *
  37. * The iterators returned by this class's <tt>iterator</tt> method are
  38. * <i>fail-fast</i>: if the set is modified at any time after the iterator is
  39. * created, in any way except through the iterator's own <tt>remove</tt>
  40. * method, the Iterator throws a <tt>ConcurrentModificationException</tt>.
  41. * Thus, in the face of concurrent modification, the iterator fails quickly
  42. * and cleanly, rather than risking arbitrary, non-deterministic behavior at
  43. * an undetermined time in the future.
  44. *
  45. * @author Josh Bloch
  46. * @version 1.15 11/29/01
  47. * @see Collection
  48. * @see Set
  49. * @see TreeSet
  50. * @see Collections#synchronizedSet(Set)
  51. * @see HashMap
  52. * @since JDK1.2
  53. */
  54. public class HashSet extends AbstractSet
  55. implements Set, Cloneable, java.io.Serializable
  56. {
  57. private transient HashMap map;
  58. // Dummy value to associate with an Object in the backing Map
  59. private static final Object PRESENT = new Object();
  60. /**
  61. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  62. * default capacity and load factor, which is <tt>0.75</tt>.
  63. */
  64. public HashSet() {
  65. map = new HashMap();
  66. }
  67. /**
  68. * Constructs a new set containing the elements in the specified
  69. * collection. The capacity of the backing <tt>HashMap</tt> instance is
  70. * twice the size of the specified collection or eleven (whichever is
  71. * greater), and the default load factor (which is <tt>0.75</tt>) is used.
  72. */
  73. public HashSet(Collection c) {
  74. map = new HashMap(Math.max(2*c.size(), 11));
  75. addAll(c);
  76. }
  77. /**
  78. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  79. * the specified initial capacity and the specified load factor.
  80. *
  81. * @param initialCapacity the initial capacity of the hash map.
  82. * @param loadFactor the load factor of the hash map.
  83. * @throws IllegalArgumentException if the initial capacity is less
  84. * than zero, or if the load factor is nonpositive.
  85. */
  86. public HashSet(int initialCapacity, float loadFactor) {
  87. map = new HashMap(initialCapacity, loadFactor);
  88. }
  89. /**
  90. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  91. * the specified initial capacity and default load factor, which is
  92. * <tt>0.75</tt>.
  93. *
  94. * @param initialCapacity the initial capacity of the hash table.
  95. * @throws IllegalArgumentException if the initial capacity is less
  96. * than zero.
  97. */
  98. public HashSet(int initialCapacity) {
  99. map = new HashMap(initialCapacity);
  100. }
  101. /**
  102. * Returns an iterator over the elements in this set. The elements
  103. * are returned in no particular order.
  104. *
  105. * @return an Iterator over the elements in this set.
  106. * @see ConcurrentModificationException
  107. */
  108. public Iterator iterator() {
  109. return map.keySet().iterator();
  110. }
  111. /**
  112. * Returns the number of elements in this set (its cardinality).
  113. *
  114. * @return the number of elements in this set (its cardinality).
  115. */
  116. public int size() {
  117. return map.size();
  118. }
  119. /**
  120. * Returns <tt>true</tt> if this set contains no elements.
  121. *
  122. * @return <tt>true</tt> if this set contains no elements.
  123. */
  124. public boolean isEmpty() {
  125. return map.isEmpty();
  126. }
  127. /**
  128. * Returns <tt>true</tt> if this set contains the specified element.
  129. *
  130. * @return <tt>true</tt> if this set contains the specified element.
  131. */
  132. public boolean contains(Object o) {
  133. return map.containsKey(o);
  134. }
  135. /**
  136. * Adds the specified element to this set if it is not already
  137. * present.
  138. *
  139. * @param o element to be added to this set.
  140. * @return <tt>true</tt> if the set did not already contain the specified
  141. * element.
  142. */
  143. public boolean add(Object o) {
  144. return map.put(o, PRESENT)==null;
  145. }
  146. /**
  147. * Removes the given element from this set if it is present.
  148. *
  149. * @param o object to be removed from this set, if present.
  150. * @return <tt>true</tt> if the set contained the specified element.
  151. */
  152. public boolean remove(Object o) {
  153. return map.remove(o)==PRESENT;
  154. }
  155. /**
  156. * Removes all of the elements from this set.
  157. */
  158. public void clear() {
  159. map.clear();
  160. }
  161. /**
  162. * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
  163. * themselves are not cloned.
  164. *
  165. * @return a shallow copy of this set.
  166. */
  167. public Object clone() {
  168. try {
  169. HashSet newSet = (HashSet)super.clone();
  170. newSet.map = (HashMap)map.clone();
  171. return newSet;
  172. } catch (CloneNotSupportedException e) {
  173. throw new InternalError();
  174. }
  175. }
  176. /**
  177. * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
  178. * serialize this set).
  179. *
  180. * @serialData The capacity of the backing <tt>HashMap</tt> instance
  181. * (int), and its load factor (float) are emitted, followed by
  182. * the size of the set (the number of elements it contains)
  183. * (int), followed by all of its elements (each an Object) in
  184. * no particular order.
  185. */
  186. private synchronized void writeObject(java.io.ObjectOutputStream s)
  187. throws java.io.IOException {
  188. // Write out any hidden serialization magic
  189. s.defaultWriteObject();
  190. // Write out HashMap capacity and load factor
  191. s.writeInt(map.capacity());
  192. s.writeFloat(map.loadFactor());
  193. // Write out size
  194. s.writeInt(map.size());
  195. // Write out all elements in the proper order.
  196. for (Iterator i=map.keySet().iterator(); i.hasNext(); )
  197. s.writeObject(i.next());
  198. }
  199. /**
  200. * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
  201. * deserialize it).
  202. */
  203. private synchronized void readObject(java.io.ObjectInputStream s)
  204. throws java.io.IOException, ClassNotFoundException {
  205. // Read in any hidden serialization magic
  206. s.defaultReadObject();
  207. // Read in HashMap capacity and load factor and create backing HashMap
  208. int capacity = s.readInt();
  209. float loadFactor = s.readFloat();
  210. map = new HashMap(capacity, loadFactor);
  211. // Read in size
  212. int size = s.readInt();
  213. // Read in all elements in the proper order.
  214. for (int i=0; i<size; i++) {
  215. Object e = s.readObject();
  216. map.put(e, PRESENT);
  217. }
  218. }
  219. }