146
147 /**
148 * The load factor for the hashtable.
149 *
150 * @serial
151 */
152 private float loadFactor;
153
154 /**
155 * The number of times this Hashtable has been structurally modified
156 * Structural modifications are those that change the number of entries in
157 * the Hashtable or otherwise modify its internal structure (e.g.,
158 * rehash). This field is used to make iterators on Collection-views of
159 * the Hashtable fail-fast. (See ConcurrentModificationException).
160 */
161 private transient int modCount = 0;
162
163 /** use serialVersionUID from JDK 1.0.2 for interoperability */
164 private static final long serialVersionUID = 1421746759512286392L;
165
166 /**
167 * Constructs a new, empty hashtable with the specified initial
168 * capacity and the specified load factor.
169 *
170 * @param initialCapacity the initial capacity of the hashtable.
171 * @param loadFactor the load factor of the hashtable.
172 * @exception IllegalArgumentException if the initial capacity is less
173 * than zero, or if the load factor is nonpositive.
174 */
175 public Hashtable(int initialCapacity, float loadFactor) {
176 if (initialCapacity < 0)
177 throw new IllegalArgumentException("Illegal Capacity: "+
178 initialCapacity);
179 if (loadFactor <= 0 || Float.isNaN(loadFactor))
180 throw new IllegalArgumentException("Illegal Load: "+loadFactor);
181
182 if (initialCapacity==0)
183 initialCapacity = 1;
184 this.loadFactor = loadFactor;
185 table = new Entry<?,?>[initialCapacity];
186 threshold = (int)(initialCapacity * loadFactor);
187 }
188
189 /**
190 * Constructs a new, empty hashtable with the specified initial capacity
191 * and default load factor (0.75).
192 *
193 * @param initialCapacity the initial capacity of the hashtable.
194 * @exception IllegalArgumentException if the initial capacity is less
195 * than zero.
196 */
197 public Hashtable(int initialCapacity) {
198 this(initialCapacity, 0.75f);
199 }
200
201 /**
202 * Constructs a new, empty hashtable with a default initial capacity (11)
203 * and load factor (0.75).
204 */
205 public Hashtable() {
206 this(11, 0.75f);
310 * specified value
311 * @throws NullPointerException if the value is <code>null</code>
312 * @since 1.2
313 */
314 public boolean containsValue(Object value) {
315 return contains(value);
316 }
317
318 /**
319 * Tests if the specified object is a key in this hashtable.
320 *
321 * @param key possible key
322 * @return <code>true</code> if and only if the specified object
323 * is a key in this hashtable, as determined by the
324 * <tt>equals</tt> method; <code>false</code> otherwise.
325 * @throws NullPointerException if the key is <code>null</code>
326 * @see #contains(Object)
327 */
328 public synchronized boolean containsKey(Object key) {
329 Entry<?,?> tab[] = table;
330 int hash = key.hashCode();
331 int index = (hash & 0x7FFFFFFF) % tab.length;
332 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
333 if ((e.hash == hash) && e.key.equals(key)) {
334 return true;
335 }
336 }
337 return false;
338 }
339
340 /**
341 * Returns the value to which the specified key is mapped,
342 * or {@code null} if this map contains no mapping for the key.
343 *
344 * <p>More formally, if this map contains a mapping from a key
345 * {@code k} to a value {@code v} such that {@code (key.equals(k))},
346 * then this method returns {@code v}; otherwise it returns
347 * {@code null}. (There can be at most one such mapping.)
348 *
349 * @param key the key whose associated value is to be returned
350 * @return the value to which the specified key is mapped, or
351 * {@code null} if this map contains no mapping for the key
352 * @throws NullPointerException if the specified key is null
353 * @see #put(Object, Object)
354 */
355 @SuppressWarnings("unchecked")
356 public synchronized V get(Object key) {
357 Entry<?,?> tab[] = table;
358 int hash = key.hashCode();
359 int index = (hash & 0x7FFFFFFF) % tab.length;
360 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
361 if ((e.hash == hash) && e.key.equals(key)) {
362 return (V)e.value;
363 }
364 }
365 return null;
366 }
367
368 /**
369 * The maximum size of array to allocate.
370 * Some VMs reserve some header words in an array.
371 * Attempts to allocate larger arrays may result in
372 * OutOfMemoryError: Requested array size exceeds VM limit
373 */
374 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
375
376 /**
377 * Increases the capacity of and internally reorganizes this
378 * hashtable, in order to accommodate and access its entries more
379 * efficiently. This method is called automatically when the
380 * number of keys in the hashtable exceeds this hashtable's capacity
381 * and load factor.
382 */
383 @SuppressWarnings("unchecked")
384 protected void rehash() {
385 int oldCapacity = table.length;
386 Entry<?,?>[] oldMap = table;
387
388 // overflow-conscious code
389 int newCapacity = (oldCapacity << 1) + 1;
390 if (newCapacity - MAX_ARRAY_SIZE > 0) {
391 if (oldCapacity == MAX_ARRAY_SIZE)
392 // Keep running with MAX_ARRAY_SIZE buckets
393 return;
394 newCapacity = MAX_ARRAY_SIZE;
395 }
396 Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
397
398 modCount++;
399 threshold = (int)(newCapacity * loadFactor);
400 table = newMap;
401
402 for (int i = oldCapacity ; i-- > 0 ;) {
403 for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
404 Entry<K,V> e = old;
405 old = old.next;
406
407 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
408 e.next = (Entry<K,V>)newMap[index];
409 newMap[index] = e;
410 }
411 }
412 }
413
414 /**
415 * Maps the specified <code>key</code> to the specified
416 * <code>value</code> in this hashtable. Neither the key nor the
417 * value can be <code>null</code>. <p>
418 *
419 * The value can be retrieved by calling the <code>get</code> method
420 * with a key that is equal to the original key.
421 *
422 * @param key the hashtable key
423 * @param value the value
424 * @return the previous value of the specified key in this hashtable,
425 * or <code>null</code> if it did not have one
426 * @exception NullPointerException if the key or value is
427 * <code>null</code>
428 * @see Object#equals(Object)
429 * @see #get(Object)
430 */
431 public synchronized V put(K key, V value) {
432 // Make sure the value is not null
433 if (value == null) {
434 throw new NullPointerException();
435 }
436
437 // Makes sure the key is not already in the hashtable.
438 Entry<?,?> tab[] = table;
439 int hash = key.hashCode();
440 int index = (hash & 0x7FFFFFFF) % tab.length;
441 @SuppressWarnings("unchecked")
442 Entry<K,V> entry = (Entry<K,V>)tab[index];
443 for(; entry != null ; entry = entry.next) {
444 if ((entry.hash == hash) && entry.key.equals(key)) {
445 V old = entry.value;
446 entry.value = value;
447 return old;
448 }
449 }
450
451 modCount++;
452 if (count >= threshold) {
453 // Rehash the table if the threshold is exceeded
454 rehash();
455
456 tab = table;
457 index = (hash & 0x7FFFFFFF) % tab.length;
458 }
459
460 // Creates the new entry.
461 @SuppressWarnings("unchecked")
462 Entry<K,V> e = (Entry<K,V>)tab[index];
463 tab[index] = new Entry<>(hash, key, value, e);
464 count++;
465 return null;
466 }
467
468 /**
469 * Removes the key (and its corresponding value) from this
470 * hashtable. This method does nothing if the key is not in the hashtable.
471 *
472 * @param key the key that needs to be removed
473 * @return the value to which the key had been mapped in this hashtable,
474 * or <code>null</code> if the key did not have a mapping
475 * @throws NullPointerException if the key is <code>null</code>
476 */
477 public synchronized V remove(Object key) {
478 Entry<?,?> tab[] = table;
479 int hash = key.hashCode();
480 int index = (hash & 0x7FFFFFFF) % tab.length;
481 @SuppressWarnings("unchecked")
482 Entry<K,V> e = (Entry<K,V>)tab[index];
483 for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
484 if ((e.hash == hash) && e.key.equals(key)) {
485 modCount++;
486 if (prev != null) {
487 prev.next = e.next;
488 } else {
489 tab[index] = e.next;
490 }
491 count--;
492 V oldValue = e.value;
493 e.value = null;
494 return oldValue;
495 }
496 }
497 return null;
498 }
499
668 if (entrySet==null)
669 entrySet = Collections.synchronizedSet(new EntrySet(), this);
670 return entrySet;
671 }
672
673 private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
674 public Iterator<Map.Entry<K,V>> iterator() {
675 return getIterator(ENTRIES);
676 }
677
678 public boolean add(Map.Entry<K,V> o) {
679 return super.add(o);
680 }
681
682 public boolean contains(Object o) {
683 if (!(o instanceof Map.Entry))
684 return false;
685 Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
686 Object key = entry.getKey();
687 Entry<?,?>[] tab = table;
688 int hash = key.hashCode();
689 int index = (hash & 0x7FFFFFFF) % tab.length;
690
691 for (Entry<?,?> e = tab[index]; e != null; e = e.next)
692 if (e.hash==hash && e.equals(entry))
693 return true;
694 return false;
695 }
696
697 public boolean remove(Object o) {
698 if (!(o instanceof Map.Entry))
699 return false;
700 Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
701 Object key = entry.getKey();
702 Entry<?,?>[] tab = table;
703 int hash = key.hashCode();
704 int index = (hash & 0x7FFFFFFF) % tab.length;
705
706 @SuppressWarnings("unchecked")
707 Entry<K,V> e = (Entry<K,V>)tab[index];
708 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
709 if (e.hash==hash && e.equals(entry)) {
710 modCount++;
711 if (prev != null)
712 prev.next = e.next;
713 else
714 tab[index] = e.next;
715
716 count--;
717 e.value = null;
718 return true;
719 }
720 }
721 return false;
722 }
723
818 * @see Map#hashCode()
819 * @since 1.2
820 */
821 public synchronized int hashCode() {
822 /*
823 * This code detects the recursion caused by computing the hash code
824 * of a self-referential hash table and prevents the stack overflow
825 * that would otherwise result. This allows certain 1.1-era
826 * applets with self-referential hash tables to work. This code
827 * abuses the loadFactor field to do double-duty as a hashCode
828 * in progress flag, so as not to worsen the space performance.
829 * A negative load factor indicates that hash code computation is
830 * in progress.
831 */
832 int h = 0;
833 if (count == 0 || loadFactor < 0)
834 return h; // Returns zero
835
836 loadFactor = -loadFactor; // Mark hashCode computation in progress
837 Entry<?,?>[] tab = table;
838 for (int i = 0; i < tab.length; i++)
839 for (Entry<?,?> e = tab[i]; e != null; e = e.next)
840 h += e.key.hashCode() ^ e.value.hashCode();
841 loadFactor = -loadFactor; // Mark hashCode computation complete
842
843 return h;
844 }
845
846 /**
847 * Save the state of the Hashtable to a stream (i.e., serialize it).
848 *
849 * @serialData The <i>capacity</i> of the Hashtable (the length of the
850 * bucket array) is emitted (int), followed by the
851 * <i>size</i> of the Hashtable (the number of key-value
852 * mappings), followed by the key (Object) and value (Object)
853 * for each key-value mapping represented by the Hashtable
854 * The key-value mappings are emitted in no particular order.
855 */
856 private void writeObject(java.io.ObjectOutputStream s)
857 throws IOException {
858 Entry<Object, Object> entryStack = null;
859
860 synchronized (this) {
877 }
878 }
879
880 // Write out the key/value objects from the stacked entries
881 while (entryStack != null) {
882 s.writeObject(entryStack.key);
883 s.writeObject(entryStack.value);
884 entryStack = entryStack.next;
885 }
886 }
887
888 /**
889 * Reconstitute the Hashtable from a stream (i.e., deserialize it).
890 */
891 private void readObject(java.io.ObjectInputStream s)
892 throws IOException, ClassNotFoundException
893 {
894 // Read in the length, threshold, and loadfactor
895 s.defaultReadObject();
896
897 // Read the original length of the array and number of elements
898 int origlength = s.readInt();
899 int elements = s.readInt();
900
901 // Compute new size with a bit of room 5% to grow but
902 // no larger than the original size. Make the length
903 // odd if it's large enough, this helps distribute the entries.
904 // Guard against the length ending up zero, that's not valid.
905 int length = (int)(elements * loadFactor) + (elements / 20) + 3;
906 if (length > elements && (length & 1) == 0)
907 length--;
908 if (origlength > 0 && length > origlength)
909 length = origlength;
910 Entry<?,?>[] table = new Entry<?,?>[length];
911 count = 0;
912
913 // Read the number of elements and then all the key/value objects
914 for (; elements > 0; elements--) {
915 @SuppressWarnings("unchecked")
916 K key = (K)s.readObject();
917 @SuppressWarnings("unchecked")
918 V value = (V)s.readObject();
919 // synch could be eliminated for performance
920 reconstitutionPut(table, key, value);
921 }
922 this.table = table;
923 }
924
925 /**
926 * The put method used by readObject. This is provided because put
927 * is overridable and should not be called in readObject since the
928 * subclass will not yet be initialized.
929 *
930 * <p>This differs from the regular put method in several ways. No
931 * checking for rehashing is necessary since the number of elements
932 * initially in the table is known. The modCount is not incremented
933 * because we are creating a new instance. Also, no return value
934 * is needed.
935 */
936 private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
937 throws StreamCorruptedException
938 {
939 if (value == null) {
940 throw new java.io.StreamCorruptedException();
941 }
942 // Makes sure the key is not already in the hashtable.
943 // This should not happen in deserialized version.
944 int hash = key.hashCode();
945 int index = (hash & 0x7FFFFFFF) % tab.length;
946 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
947 if ((e.hash == hash) && e.key.equals(key)) {
948 throw new java.io.StreamCorruptedException();
949 }
950 }
951 // Creates the new entry.
952 @SuppressWarnings("unchecked")
953 Entry<K,V> e = (Entry<K,V>)tab[index];
954 tab[index] = new Entry<>(hash, key, value, e);
955 count++;
956 }
957
958 /**
959 * Hashtable collision list.
960 */
961 private static class Entry<K,V> implements Map.Entry<K,V> {
962 int hash;
963 K key;
964 V value;
965 Entry<K,V> next;
966
967 protected Entry(int hash, K key, V value, Entry<K,V> next) {
968 this.hash = hash;
969 this.key = key;
970 this.value = value;
971 this.next = next;
972 }
973
974 @SuppressWarnings("unchecked")
975 protected Object clone() {
976 return new Entry<>(hash, key, value,
977 (next==null ? null : (Entry<K,V>) next.clone()));
978 }
979
980 // Map.Entry Ops
981
982 public K getKey() {
|
146
147 /**
148 * The load factor for the hashtable.
149 *
150 * @serial
151 */
152 private float loadFactor;
153
154 /**
155 * The number of times this Hashtable has been structurally modified
156 * Structural modifications are those that change the number of entries in
157 * the Hashtable or otherwise modify its internal structure (e.g.,
158 * rehash). This field is used to make iterators on Collection-views of
159 * the Hashtable fail-fast. (See ConcurrentModificationException).
160 */
161 private transient int modCount = 0;
162
163 /** use serialVersionUID from JDK 1.0.2 for interoperability */
164 private static final long serialVersionUID = 1421746759512286392L;
165
166 private static class Holder {
167 // Unsafe mechanics
168 /**
169 *
170 */
171 private static final sun.misc.Unsafe UNSAFE;
172
173 /**
174 * Offset of "final" hashmask field we must set in
175 * readObject() method.
176 */
177 private static final long HASHMASK_OFFSET;
178
179 static {
180 try {
181 UNSAFE = sun.misc.Unsafe.getUnsafe();
182 HASHMASK_OFFSET = UNSAFE.objectFieldOffset(
183 Hashtable.class.getDeclaredField("hashMask"));
184 } catch (NoSuchFieldException | SecurityException e) {
185 throw new InternalError("Failed to record hashMask offset", e);
186 }
187 }
188 }
189
190 /**
191 * A random mask value that is used for hashcode values associated with this
192 * instance to make hash collisions harder to find.
193 */
194 transient final int hashMask = sun.misc.Hashing.makeHashMask(this);
195
196 private int hash(Object k) {
197 int h = hashMask;
198 if (0 != h) {
199 if (k instanceof String) {
200 h ^= ((String)k).hash32();
201 } else {
202 h ^= k.hashCode();
203
204 // This function ensures that hashCodes that differ only by
205 // constant multiples at each bit position have a bounded
206 // number of collisions (approximately 8 at default load factor).
207 h ^= (h >>> 20) ^ (h >>> 12);
208 h ^= (h >>> 7) ^ (h >>> 4);
209 }
210 } else {
211 h = k.hashCode();
212 }
213
214 return h;
215 }
216
217 /**
218 * Constructs a new, empty hashtable with the specified initial
219 * capacity and the specified load factor.
220 *
221 * @param initialCapacity the initial capacity of the hashtable.
222 * @param loadFactor the load factor of the hashtable.
223 * @exception IllegalArgumentException if the initial capacity is less
224 * than zero, or if the load factor is nonpositive.
225 */
226 public Hashtable(int initialCapacity, float loadFactor) {
227 if (initialCapacity < 0)
228 throw new IllegalArgumentException("Illegal Capacity: "+
229 initialCapacity);
230 if (loadFactor <= 0 || Float.isNaN(loadFactor))
231 throw new IllegalArgumentException("Illegal Load: "+loadFactor);
232
233 if (initialCapacity==0)
234 initialCapacity = 1;
235 this.loadFactor = loadFactor;
236 table = new Entry<?,?>[initialCapacity];
237 threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
238 }
239
240 /**
241 * Constructs a new, empty hashtable with the specified initial capacity
242 * and default load factor (0.75).
243 *
244 * @param initialCapacity the initial capacity of the hashtable.
245 * @exception IllegalArgumentException if the initial capacity is less
246 * than zero.
247 */
248 public Hashtable(int initialCapacity) {
249 this(initialCapacity, 0.75f);
250 }
251
252 /**
253 * Constructs a new, empty hashtable with a default initial capacity (11)
254 * and load factor (0.75).
255 */
256 public Hashtable() {
257 this(11, 0.75f);
361 * specified value
362 * @throws NullPointerException if the value is <code>null</code>
363 * @since 1.2
364 */
365 public boolean containsValue(Object value) {
366 return contains(value);
367 }
368
369 /**
370 * Tests if the specified object is a key in this hashtable.
371 *
372 * @param key possible key
373 * @return <code>true</code> if and only if the specified object
374 * is a key in this hashtable, as determined by the
375 * <tt>equals</tt> method; <code>false</code> otherwise.
376 * @throws NullPointerException if the key is <code>null</code>
377 * @see #contains(Object)
378 */
379 public synchronized boolean containsKey(Object key) {
380 Entry<?,?> tab[] = table;
381 int hash = hash(key);
382 int index = (hash & 0x7FFFFFFF) % tab.length;
383 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
384 if ((e.hash == hash) && e.key.equals(key)) {
385 return true;
386 }
387 }
388 return false;
389 }
390
391 /**
392 * Returns the value to which the specified key is mapped,
393 * or {@code null} if this map contains no mapping for the key.
394 *
395 * <p>More formally, if this map contains a mapping from a key
396 * {@code k} to a value {@code v} such that {@code (key.equals(k))},
397 * then this method returns {@code v}; otherwise it returns
398 * {@code null}. (There can be at most one such mapping.)
399 *
400 * @param key the key whose associated value is to be returned
401 * @return the value to which the specified key is mapped, or
402 * {@code null} if this map contains no mapping for the key
403 * @throws NullPointerException if the specified key is null
404 * @see #put(Object, Object)
405 */
406 @SuppressWarnings("unchecked")
407 public synchronized V get(Object key) {
408 Entry<?,?> tab[] = table;
409 int hash = hash(key);
410 int index = (hash & 0x7FFFFFFF) % tab.length;
411 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
412 if ((e.hash == hash) && e.key.equals(key)) {
413 return (V)e.value;
414 }
415 }
416 return null;
417 }
418
419 /**
420 * The maximum size of array to allocate.
421 * Some VMs reserve some header words in an array.
422 * Attempts to allocate larger arrays may result in
423 * OutOfMemoryError: Requested array size exceeds VM limit
424 */
425 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
426
427 /**
428 * Increases the capacity of and internally reorganizes this
429 * hashtable, in order to accommodate and access its entries more
430 * efficiently. This method is called automatically when the
431 * number of keys in the hashtable exceeds this hashtable's capacity
432 * and load factor.
433 */
434 @SuppressWarnings("unchecked")
435 protected void rehash() {
436 int oldCapacity = table.length;
437 Entry<?,?>[] oldMap = table;
438
439 // overflow-conscious code
440 int newCapacity = (oldCapacity << 1) + 1;
441 if (newCapacity - MAX_ARRAY_SIZE > 0) {
442 if (oldCapacity == MAX_ARRAY_SIZE)
443 // Keep running with MAX_ARRAY_SIZE buckets
444 return;
445 newCapacity = MAX_ARRAY_SIZE;
446 }
447 Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
448
449 modCount++;
450 threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
451 table = newMap;
452
453 for (int i = oldCapacity ; i-- > 0 ;) {
454 for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
455 Entry<K,V> e = old;
456 old = old.next;
457
458 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
459 e.next = (Entry<K,V>)newMap[index];
460 newMap[index] = e;
461 }
462 }
463 }
464
465 /**
466 * Maps the specified <code>key</code> to the specified
467 * <code>value</code> in this hashtable. Neither the key nor the
468 * value can be <code>null</code>. <p>
469 *
470 * The value can be retrieved by calling the <code>get</code> method
471 * with a key that is equal to the original key.
472 *
473 * @param key the hashtable key
474 * @param value the value
475 * @return the previous value of the specified key in this hashtable,
476 * or <code>null</code> if it did not have one
477 * @exception NullPointerException if the key or value is
478 * <code>null</code>
479 * @see Object#equals(Object)
480 * @see #get(Object)
481 */
482 public synchronized V put(K key, V value) {
483 // Make sure the value is not null
484 if (value == null) {
485 throw new NullPointerException();
486 }
487
488 // Makes sure the key is not already in the hashtable.
489 Entry<?,?> tab[] = table;
490 int hash = hash(key);
491 int index = (hash & 0x7FFFFFFF) % tab.length;
492 @SuppressWarnings("unchecked")
493 Entry<K,V> entry = (Entry<K,V>)tab[index];
494 for(; entry != null ; entry = entry.next) {
495 if ((entry.hash == hash) && entry.key.equals(key)) {
496 V old = entry.value;
497 entry.value = value;
498 return old;
499 }
500 }
501
502 modCount++;
503 if (count >= threshold) {
504 // Rehash the table if the threshold is exceeded
505 rehash();
506
507 tab = table;
508 hash = hash(key);
509 index = (hash & 0x7FFFFFFF) % tab.length;
510 }
511
512 // Creates the new entry.
513 @SuppressWarnings("unchecked")
514 Entry<K,V> e = (Entry<K,V>)tab[index];
515 tab[index] = new Entry<>(hash, key, value, e);
516 count++;
517 return null;
518 }
519
520 /**
521 * Removes the key (and its corresponding value) from this
522 * hashtable. This method does nothing if the key is not in the hashtable.
523 *
524 * @param key the key that needs to be removed
525 * @return the value to which the key had been mapped in this hashtable,
526 * or <code>null</code> if the key did not have a mapping
527 * @throws NullPointerException if the key is <code>null</code>
528 */
529 public synchronized V remove(Object key) {
530 Entry<?,?> tab[] = table;
531 int hash = hash(key);
532 int index = (hash & 0x7FFFFFFF) % tab.length;
533 @SuppressWarnings("unchecked")
534 Entry<K,V> e = (Entry<K,V>)tab[index];
535 for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
536 if ((e.hash == hash) && e.key.equals(key)) {
537 modCount++;
538 if (prev != null) {
539 prev.next = e.next;
540 } else {
541 tab[index] = e.next;
542 }
543 count--;
544 V oldValue = e.value;
545 e.value = null;
546 return oldValue;
547 }
548 }
549 return null;
550 }
551
720 if (entrySet==null)
721 entrySet = Collections.synchronizedSet(new EntrySet(), this);
722 return entrySet;
723 }
724
725 private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
726 public Iterator<Map.Entry<K,V>> iterator() {
727 return getIterator(ENTRIES);
728 }
729
730 public boolean add(Map.Entry<K,V> o) {
731 return super.add(o);
732 }
733
734 public boolean contains(Object o) {
735 if (!(o instanceof Map.Entry))
736 return false;
737 Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
738 Object key = entry.getKey();
739 Entry<?,?>[] tab = table;
740 int hash = hash(key);
741 int index = (hash & 0x7FFFFFFF) % tab.length;
742
743 for (Entry<?,?> e = tab[index]; e != null; e = e.next)
744 if (e.hash==hash && e.equals(entry))
745 return true;
746 return false;
747 }
748
749 public boolean remove(Object o) {
750 if (!(o instanceof Map.Entry))
751 return false;
752 Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
753 Object key = entry.getKey();
754 Entry<?,?>[] tab = table;
755 int hash = hash(key);
756 int index = (hash & 0x7FFFFFFF) % tab.length;
757
758 @SuppressWarnings("unchecked")
759 Entry<K,V> e = (Entry<K,V>)tab[index];
760 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
761 if (e.hash==hash && e.equals(entry)) {
762 modCount++;
763 if (prev != null)
764 prev.next = e.next;
765 else
766 tab[index] = e.next;
767
768 count--;
769 e.value = null;
770 return true;
771 }
772 }
773 return false;
774 }
775
870 * @see Map#hashCode()
871 * @since 1.2
872 */
873 public synchronized int hashCode() {
874 /*
875 * This code detects the recursion caused by computing the hash code
876 * of a self-referential hash table and prevents the stack overflow
877 * that would otherwise result. This allows certain 1.1-era
878 * applets with self-referential hash tables to work. This code
879 * abuses the loadFactor field to do double-duty as a hashCode
880 * in progress flag, so as not to worsen the space performance.
881 * A negative load factor indicates that hash code computation is
882 * in progress.
883 */
884 int h = 0;
885 if (count == 0 || loadFactor < 0)
886 return h; // Returns zero
887
888 loadFactor = -loadFactor; // Mark hashCode computation in progress
889 Entry<?,?>[] tab = table;
890 for (Entry<?,?> entry : tab) {
891 while (entry != null) {
892 h += entry.hashCode();
893 entry = entry.next;
894 }
895 }
896
897 loadFactor = -loadFactor; // Mark hashCode computation complete
898
899 return h;
900 }
901
902 /**
903 * Save the state of the Hashtable to a stream (i.e., serialize it).
904 *
905 * @serialData The <i>capacity</i> of the Hashtable (the length of the
906 * bucket array) is emitted (int), followed by the
907 * <i>size</i> of the Hashtable (the number of key-value
908 * mappings), followed by the key (Object) and value (Object)
909 * for each key-value mapping represented by the Hashtable
910 * The key-value mappings are emitted in no particular order.
911 */
912 private void writeObject(java.io.ObjectOutputStream s)
913 throws IOException {
914 Entry<Object, Object> entryStack = null;
915
916 synchronized (this) {
933 }
934 }
935
936 // Write out the key/value objects from the stacked entries
937 while (entryStack != null) {
938 s.writeObject(entryStack.key);
939 s.writeObject(entryStack.value);
940 entryStack = entryStack.next;
941 }
942 }
943
944 /**
945 * Reconstitute the Hashtable from a stream (i.e., deserialize it).
946 */
947 private void readObject(java.io.ObjectInputStream s)
948 throws IOException, ClassNotFoundException
949 {
950 // Read in the length, threshold, and loadfactor
951 s.defaultReadObject();
952
953 // set hashMask
954 Holder.UNSAFE.putIntVolatile(this, Holder.HASHMASK_OFFSET,
955 sun.misc.Hashing.makeHashMask(this));
956
957 // Read the original length of the array and number of elements
958 int origlength = s.readInt();
959 int elements = s.readInt();
960
961 // Compute new size with a bit of room 5% to grow but
962 // no larger than the original size. Make the length
963 // odd if it's large enough, this helps distribute the entries.
964 // Guard against the length ending up zero, that's not valid.
965 int length = (int)(elements * loadFactor) + (elements / 20) + 3;
966 if (length > elements && (length & 1) == 0)
967 length--;
968 if (origlength > 0 && length > origlength)
969 length = origlength;
970 table = new Entry<?,?>[length];
971 threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
972 count = 0;
973
974 // Read the number of elements and then all the key/value objects
975 for (; elements > 0; elements--) {
976 @SuppressWarnings("unchecked")
977 K key = (K)s.readObject();
978 @SuppressWarnings("unchecked")
979 V value = (V)s.readObject();
980 // synch could be eliminated for performance
981 reconstitutionPut(table, key, value);
982 }
983 }
984
985 /**
986 * The put method used by readObject. This is provided because put
987 * is overridable and should not be called in readObject since the
988 * subclass will not yet be initialized.
989 *
990 * <p>This differs from the regular put method in several ways. No
991 * checking for rehashing is necessary since the number of elements
992 * initially in the table is known. The modCount is not incremented
993 * because we are creating a new instance. Also, no return value
994 * is needed.
995 */
996 private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
997 throws StreamCorruptedException
998 {
999 if (value == null) {
1000 throw new java.io.StreamCorruptedException();
1001 }
1002 // Makes sure the key is not already in the hashtable.
1003 // This should not happen in deserialized version.
1004 int hash = hash(key);
1005 int index = (hash & 0x7FFFFFFF) % tab.length;
1006 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
1007 if ((e.hash == hash) && e.key.equals(key)) {
1008 throw new java.io.StreamCorruptedException();
1009 }
1010 }
1011 // Creates the new entry.
1012 @SuppressWarnings("unchecked")
1013 Entry<K,V> e = (Entry<K,V>)tab[index];
1014 tab[index] = new Entry<>(hash, key, value, e);
1015 count++;
1016 }
1017
1018 /**
1019 * Hashtable bucket collision list entry
1020 */
1021 private static class Entry<K,V> implements Map.Entry<K,V> {
1022 final int hash;
1023 K key;
1024 V value;
1025 Entry<K,V> next;
1026
1027 protected Entry(int hash, K key, V value, Entry<K,V> next) {
1028 this.hash = hash;
1029 this.key = key;
1030 this.value = value;
1031 this.next = next;
1032 }
1033
1034 @SuppressWarnings("unchecked")
1035 protected Object clone() {
1036 return new Entry<>(hash, key, value,
1037 (next==null ? null : (Entry<K,V>) next.clone()));
1038 }
1039
1040 // Map.Entry Ops
1041
1042 public K getKey() {
|