1. /*
  2. * @(#)HashSet.java 1.33 03/12/19
  3. *
  4. * Copyright 2004 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 initial 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. * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
  46. * as it is, generally speaking, impossible to make any hard guarantees in the
  47. * presence of unsynchronized concurrent modification. Fail-fast iterators
  48. * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
  49. * Therefore, it would be wrong to write a program that depended on this
  50. * exception for its correctness: <i>the fail-fast behavior of iterators
  51. * should be used only to detect bugs.</i><p>
  52. *
  53. * This class is a member of the
  54. * <a href="{@docRoot}/../guide/collections/index.html">
  55. * Java Collections Framework</a>.
  56. *
  57. * @author Josh Bloch
  58. * @author Neal Gafter
  59. * @version 1.33, 12/19/03
  60. * @see Collection
  61. * @see Set
  62. * @see TreeSet
  63. * @see Collections#synchronizedSet(Set)
  64. * @see HashMap
  65. * @since 1.2
  66. */
  67. public class HashSet<E>
  68. extends AbstractSet<E>
  69. implements Set<E>, Cloneable, java.io.Serializable
  70. {
  71. static final long serialVersionUID = -5024744406713321676L;
  72. private transient HashMap<E,Object> map;
  73. // Dummy value to associate with an Object in the backing Map
  74. private static final Object PRESENT = new Object();
  75. /**
  76. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  77. * default initial capacity (16) and load factor (0.75).
  78. */
  79. public HashSet() {
  80. map = new HashMap<E,Object>();
  81. }
  82. /**
  83. * Constructs a new set containing the elements in the specified
  84. * collection. The <tt>HashMap</tt> is created with default load factor
  85. * (0.75) and an initial capacity sufficient to contain the elements in
  86. * the specified collection.
  87. *
  88. * @param c the collection whose elements are to be placed into this set.
  89. * @throws NullPointerException if the specified collection is null.
  90. */
  91. public HashSet(Collection<? extends E> c) {
  92. map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
  93. addAll(c);
  94. }
  95. /**
  96. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  97. * the specified initial capacity and the specified load factor.
  98. *
  99. * @param initialCapacity the initial capacity of the hash map.
  100. * @param loadFactor the load factor of the hash map.
  101. * @throws IllegalArgumentException if the initial capacity is less
  102. * than zero, or if the load factor is nonpositive.
  103. */
  104. public HashSet(int initialCapacity, float loadFactor) {
  105. map = new HashMap<E,Object>(initialCapacity, loadFactor);
  106. }
  107. /**
  108. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  109. * the specified initial capacity and default load factor, which is
  110. * <tt>0.75</tt>.
  111. *
  112. * @param initialCapacity the initial capacity of the hash table.
  113. * @throws IllegalArgumentException if the initial capacity is less
  114. * than zero.
  115. */
  116. public HashSet(int initialCapacity) {
  117. map = new HashMap<E,Object>(initialCapacity);
  118. }
  119. /**
  120. * Constructs a new, empty linked hash set. (This package private
  121. * constructor is only used by LinkedHashSet.) The backing
  122. * HashMap instance is a LinkedHashMap with the specified initial
  123. * capacity and the specified load factor.
  124. *
  125. * @param initialCapacity the initial capacity of the hash map.
  126. * @param loadFactor the load factor of the hash map.
  127. * @param dummy ignored (distinguishes this
  128. * constructor from other int, float constructor.)
  129. * @throws IllegalArgumentException if the initial capacity is less
  130. * than zero, or if the load factor is nonpositive.
  131. */
  132. HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  133. map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
  134. }
  135. /**
  136. * Returns an iterator over the elements in this set. The elements
  137. * are returned in no particular order.
  138. *
  139. * @return an Iterator over the elements in this set.
  140. * @see ConcurrentModificationException
  141. */
  142. public Iterator<E> iterator() {
  143. return map.keySet().iterator();
  144. }
  145. /**
  146. * Returns the number of elements in this set (its cardinality).
  147. *
  148. * @return the number of elements in this set (its cardinality).
  149. */
  150. public int size() {
  151. return map.size();
  152. }
  153. /**
  154. * Returns <tt>true</tt> if this set contains no elements.
  155. *
  156. * @return <tt>true</tt> if this set contains no elements.
  157. */
  158. public boolean isEmpty() {
  159. return map.isEmpty();
  160. }
  161. /**
  162. * Returns <tt>true</tt> if this set contains the specified element.
  163. *
  164. * @param o element whose presence in this set is to be tested.
  165. * @return <tt>true</tt> if this set contains the specified element.
  166. */
  167. public boolean contains(Object o) {
  168. return map.containsKey(o);
  169. }
  170. /**
  171. * Adds the specified element to this set if it is not already
  172. * present.
  173. *
  174. * @param o element to be added to this set.
  175. * @return <tt>true</tt> if the set did not already contain the specified
  176. * element.
  177. */
  178. public boolean add(E o) {
  179. return map.put(o, PRESENT)==null;
  180. }
  181. /**
  182. * Removes the specified element from this set if it is present.
  183. *
  184. * @param o object to be removed from this set, if present.
  185. * @return <tt>true</tt> if the set contained the specified element.
  186. */
  187. public boolean remove(Object o) {
  188. return map.remove(o)==PRESENT;
  189. }
  190. /**
  191. * Removes all of the elements from this set.
  192. */
  193. public void clear() {
  194. map.clear();
  195. }
  196. /**
  197. * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
  198. * themselves are not cloned.
  199. *
  200. * @return a shallow copy of this set.
  201. */
  202. public Object clone() {
  203. try {
  204. HashSet<E> newSet = (HashSet<E>) super.clone();
  205. newSet.map = (HashMap<E, Object>) map.clone();
  206. return newSet;
  207. } catch (CloneNotSupportedException e) {
  208. throw new InternalError();
  209. }
  210. }
  211. /**
  212. * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
  213. * serialize this set).
  214. *
  215. * @serialData The capacity of the backing <tt>HashMap</tt> instance
  216. * (int), and its load factor (float) are emitted, followed by
  217. * the size of the set (the number of elements it contains)
  218. * (int), followed by all of its elements (each an Object) in
  219. * no particular order.
  220. */
  221. private void writeObject(java.io.ObjectOutputStream s)
  222. throws java.io.IOException {
  223. // Write out any hidden serialization magic
  224. s.defaultWriteObject();
  225. // Write out HashMap capacity and load factor
  226. s.writeInt(map.capacity());
  227. s.writeFloat(map.loadFactor());
  228. // Write out size
  229. s.writeInt(map.size());
  230. // Write out all elements in the proper order.
  231. for (Iterator i=map.keySet().iterator(); i.hasNext(); )
  232. s.writeObject(i.next());
  233. }
  234. /**
  235. * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
  236. * deserialize it).
  237. */
  238. private void readObject(java.io.ObjectInputStream s)
  239. throws java.io.IOException, ClassNotFoundException {
  240. // Read in any hidden serialization magic
  241. s.defaultReadObject();
  242. // Read in HashMap capacity and load factor and create backing HashMap
  243. int capacity = s.readInt();
  244. float loadFactor = s.readFloat();
  245. map = (((HashSet)this) instanceof LinkedHashSet ?
  246. new LinkedHashMap<E,Object>(capacity, loadFactor) :
  247. new HashMap<E,Object>(capacity, loadFactor));
  248. // Read in size
  249. int size = s.readInt();
  250. // Read in all elements in the proper order.
  251. for (int i=0; i<size; i++) {
  252. E e = (E) s.readObject();
  253. map.put(e, PRESENT);
  254. }
  255. }
  256. }