Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/util/Hashtable.java
38829 views
1
/*
2
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package java.util;
27
28
import java.io.*;
29
import java.util.concurrent.ThreadLocalRandom;
30
import java.util.function.BiConsumer;
31
import java.util.function.Function;
32
import java.util.function.BiFunction;
33
import sun.misc.SharedSecrets;
34
35
/**
36
* This class implements a hash table, which maps keys to values. Any
37
* non-<code>null</code> object can be used as a key or as a value. <p>
38
*
39
* To successfully store and retrieve objects from a hashtable, the
40
* objects used as keys must implement the <code>hashCode</code>
41
* method and the <code>equals</code> method. <p>
42
*
43
* An instance of <code>Hashtable</code> has two parameters that affect its
44
* performance: <i>initial capacity</i> and <i>load factor</i>. The
45
* <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
46
* <i>initial capacity</i> is simply the capacity at the time the hash table
47
* is created. Note that the hash table is <i>open</i>: in the case of a "hash
48
* collision", a single bucket stores multiple entries, which must be searched
49
* sequentially. The <i>load factor</i> is a measure of how full the hash
50
* table is allowed to get before its capacity is automatically increased.
51
* The initial capacity and load factor parameters are merely hints to
52
* the implementation. The exact details as to when and whether the rehash
53
* method is invoked are implementation-dependent.<p>
54
*
55
* Generally, the default load factor (.75) offers a good tradeoff between
56
* time and space costs. Higher values decrease the space overhead but
57
* increase the time cost to look up an entry (which is reflected in most
58
* <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
59
*
60
* The initial capacity controls a tradeoff between wasted space and the
61
* need for <code>rehash</code> operations, which are time-consuming.
62
* No <code>rehash</code> operations will <i>ever</i> occur if the initial
63
* capacity is greater than the maximum number of entries the
64
* <tt>Hashtable</tt> will contain divided by its load factor. However,
65
* setting the initial capacity too high can waste space.<p>
66
*
67
* If many entries are to be made into a <code>Hashtable</code>,
68
* creating it with a sufficiently large capacity may allow the
69
* entries to be inserted more efficiently than letting it perform
70
* automatic rehashing as needed to grow the table. <p>
71
*
72
* This example creates a hashtable of numbers. It uses the names of
73
* the numbers as keys:
74
* <pre> {@code
75
* Hashtable<String, Integer> numbers
76
* = new Hashtable<String, Integer>();
77
* numbers.put("one", 1);
78
* numbers.put("two", 2);
79
* numbers.put("three", 3);}</pre>
80
*
81
* <p>To retrieve a number, use the following code:
82
* <pre> {@code
83
* Integer n = numbers.get("two");
84
* if (n != null) {
85
* System.out.println("two = " + n);
86
* }}</pre>
87
*
88
* <p>The iterators returned by the <tt>iterator</tt> method of the collections
89
* returned by all of this class's "collection view methods" are
90
* <em>fail-fast</em>: if the Hashtable is structurally modified at any time
91
* after the iterator is created, in any way except through the iterator's own
92
* <tt>remove</tt> method, the iterator will throw a {@link
93
* ConcurrentModificationException}. Thus, in the face of concurrent
94
* modification, the iterator fails quickly and cleanly, rather than risking
95
* arbitrary, non-deterministic behavior at an undetermined time in the future.
96
* The Enumerations returned by Hashtable's keys and elements methods are
97
* <em>not</em> fail-fast.
98
*
99
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
100
* as it is, generally speaking, impossible to make any hard guarantees in the
101
* presence of unsynchronized concurrent modification. Fail-fast iterators
102
* throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
103
* Therefore, it would be wrong to write a program that depended on this
104
* exception for its correctness: <i>the fail-fast behavior of iterators
105
* should be used only to detect bugs.</i>
106
*
107
* <p>As of the Java 2 platform v1.2, this class was retrofitted to
108
* implement the {@link Map} interface, making it a member of the
109
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
110
*
111
* Java Collections Framework</a>. Unlike the new collection
112
* implementations, {@code Hashtable} is synchronized. If a
113
* thread-safe implementation is not needed, it is recommended to use
114
* {@link HashMap} in place of {@code Hashtable}. If a thread-safe
115
* highly-concurrent implementation is desired, then it is recommended
116
* to use {@link java.util.concurrent.ConcurrentHashMap} in place of
117
* {@code Hashtable}.
118
*
119
* @author Arthur van Hoff
120
* @author Josh Bloch
121
* @author Neal Gafter
122
* @see Object#equals(java.lang.Object)
123
* @see Object#hashCode()
124
* @see Hashtable#rehash()
125
* @see Collection
126
* @see Map
127
* @see HashMap
128
* @see TreeMap
129
* @since JDK1.0
130
*/
131
public class Hashtable<K,V>
132
extends Dictionary<K,V>
133
implements Map<K,V>, Cloneable, java.io.Serializable {
134
135
/**
136
* The hash table data.
137
*/
138
private transient Entry<?,?>[] table;
139
140
/**
141
* The total number of entries in the hash table.
142
*/
143
private transient int count;
144
145
/**
146
* The table is rehashed when its size exceeds this threshold. (The
147
* value of this field is (int)(capacity * loadFactor).)
148
*
149
* @serial
150
*/
151
private int threshold;
152
153
/**
154
* The load factor for the hashtable.
155
*
156
* @serial
157
*/
158
private float loadFactor;
159
160
/**
161
* The number of times this Hashtable has been structurally modified
162
* Structural modifications are those that change the number of entries in
163
* the Hashtable or otherwise modify its internal structure (e.g.,
164
* rehash). This field is used to make iterators on Collection-views of
165
* the Hashtable fail-fast. (See ConcurrentModificationException).
166
*/
167
private transient int modCount = 0;
168
169
/** use serialVersionUID from JDK 1.0.2 for interoperability */
170
private static final long serialVersionUID = 1421746759512286392L;
171
172
/**
173
* Constructs a new, empty hashtable with the specified initial
174
* capacity and the specified load factor.
175
*
176
* @param initialCapacity the initial capacity of the hashtable.
177
* @param loadFactor the load factor of the hashtable.
178
* @exception IllegalArgumentException if the initial capacity is less
179
* than zero, or if the load factor is nonpositive.
180
*/
181
public Hashtable(int initialCapacity, float loadFactor) {
182
if (initialCapacity < 0)
183
throw new IllegalArgumentException("Illegal Capacity: "+
184
initialCapacity);
185
if (loadFactor <= 0 || Float.isNaN(loadFactor))
186
throw new IllegalArgumentException("Illegal Load: "+loadFactor);
187
188
if (initialCapacity==0)
189
initialCapacity = 1;
190
this.loadFactor = loadFactor;
191
table = new Entry<?,?>[initialCapacity];
192
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
193
}
194
195
/**
196
* Constructs a new, empty hashtable with the specified initial capacity
197
* and default load factor (0.75).
198
*
199
* @param initialCapacity the initial capacity of the hashtable.
200
* @exception IllegalArgumentException if the initial capacity is less
201
* than zero.
202
*/
203
public Hashtable(int initialCapacity) {
204
this(initialCapacity, 0.75f);
205
}
206
207
/**
208
* Constructs a new, empty hashtable with a default initial capacity (11)
209
* and load factor (0.75).
210
*/
211
public Hashtable() {
212
this(11, 0.75f);
213
}
214
215
/**
216
* Constructs a new hashtable with the same mappings as the given
217
* Map. The hashtable is created with an initial capacity sufficient to
218
* hold the mappings in the given Map and a default load factor (0.75).
219
*
220
* @param t the map whose mappings are to be placed in this map.
221
* @throws NullPointerException if the specified map is null.
222
* @since 1.2
223
*/
224
public Hashtable(Map<? extends K, ? extends V> t) {
225
this(Math.max(2*t.size(), 11), 0.75f);
226
putAll(t);
227
}
228
229
/**
230
* Returns the number of keys in this hashtable.
231
*
232
* @return the number of keys in this hashtable.
233
*/
234
public synchronized int size() {
235
return count;
236
}
237
238
/**
239
* Tests if this hashtable maps no keys to values.
240
*
241
* @return <code>true</code> if this hashtable maps no keys to values;
242
* <code>false</code> otherwise.
243
*/
244
public synchronized boolean isEmpty() {
245
return count == 0;
246
}
247
248
/**
249
* Returns an enumeration of the keys in this hashtable.
250
*
251
* @return an enumeration of the keys in this hashtable.
252
* @see Enumeration
253
* @see #elements()
254
* @see #keySet()
255
* @see Map
256
*/
257
public synchronized Enumeration<K> keys() {
258
return this.<K>getEnumeration(KEYS);
259
}
260
261
/**
262
* Returns an enumeration of the values in this hashtable.
263
* Use the Enumeration methods on the returned object to fetch the elements
264
* sequentially.
265
*
266
* @return an enumeration of the values in this hashtable.
267
* @see java.util.Enumeration
268
* @see #keys()
269
* @see #values()
270
* @see Map
271
*/
272
public synchronized Enumeration<V> elements() {
273
return this.<V>getEnumeration(VALUES);
274
}
275
276
/**
277
* Tests if some key maps into the specified value in this hashtable.
278
* This operation is more expensive than the {@link #containsKey
279
* containsKey} method.
280
*
281
* <p>Note that this method is identical in functionality to
282
* {@link #containsValue containsValue}, (which is part of the
283
* {@link Map} interface in the collections framework).
284
*
285
* @param value a value to search for
286
* @return <code>true</code> if and only if some key maps to the
287
* <code>value</code> argument in this hashtable as
288
* determined by the <tt>equals</tt> method;
289
* <code>false</code> otherwise.
290
* @exception NullPointerException if the value is <code>null</code>
291
*/
292
public synchronized boolean contains(Object value) {
293
if (value == null) {
294
throw new NullPointerException();
295
}
296
297
Entry<?,?> tab[] = table;
298
for (int i = tab.length ; i-- > 0 ;) {
299
for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
300
if (e.value.equals(value)) {
301
return true;
302
}
303
}
304
}
305
return false;
306
}
307
308
/**
309
* Returns true if this hashtable maps one or more keys to this value.
310
*
311
* <p>Note that this method is identical in functionality to {@link
312
* #contains contains} (which predates the {@link Map} interface).
313
*
314
* @param value value whose presence in this hashtable is to be tested
315
* @return <tt>true</tt> if this map maps one or more keys to the
316
* specified value
317
* @throws NullPointerException if the value is <code>null</code>
318
* @since 1.2
319
*/
320
public boolean containsValue(Object value) {
321
return contains(value);
322
}
323
324
/**
325
* Tests if the specified object is a key in this hashtable.
326
*
327
* @param key possible key
328
* @return <code>true</code> if and only if the specified object
329
* is a key in this hashtable, as determined by the
330
* <tt>equals</tt> method; <code>false</code> otherwise.
331
* @throws NullPointerException if the key is <code>null</code>
332
* @see #contains(Object)
333
*/
334
public synchronized boolean containsKey(Object key) {
335
Entry<?,?> tab[] = table;
336
int hash = key.hashCode();
337
int index = (hash & 0x7FFFFFFF) % tab.length;
338
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
339
if ((e.hash == hash) && e.key.equals(key)) {
340
return true;
341
}
342
}
343
return false;
344
}
345
346
/**
347
* Returns the value to which the specified key is mapped,
348
* or {@code null} if this map contains no mapping for the key.
349
*
350
* <p>More formally, if this map contains a mapping from a key
351
* {@code k} to a value {@code v} such that {@code (key.equals(k))},
352
* then this method returns {@code v}; otherwise it returns
353
* {@code null}. (There can be at most one such mapping.)
354
*
355
* @param key the key whose associated value is to be returned
356
* @return the value to which the specified key is mapped, or
357
* {@code null} if this map contains no mapping for the key
358
* @throws NullPointerException if the specified key is null
359
* @see #put(Object, Object)
360
*/
361
@SuppressWarnings("unchecked")
362
public synchronized V get(Object key) {
363
Entry<?,?> tab[] = table;
364
int hash = key.hashCode();
365
int index = (hash & 0x7FFFFFFF) % tab.length;
366
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
367
if ((e.hash == hash) && e.key.equals(key)) {
368
return (V)e.value;
369
}
370
}
371
return null;
372
}
373
374
/**
375
* The maximum size of array to allocate.
376
* Some VMs reserve some header words in an array.
377
* Attempts to allocate larger arrays may result in
378
* OutOfMemoryError: Requested array size exceeds VM limit
379
*/
380
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
381
382
/**
383
* Increases the capacity of and internally reorganizes this
384
* hashtable, in order to accommodate and access its entries more
385
* efficiently. This method is called automatically when the
386
* number of keys in the hashtable exceeds this hashtable's capacity
387
* and load factor.
388
*/
389
@SuppressWarnings("unchecked")
390
protected void rehash() {
391
int oldCapacity = table.length;
392
Entry<?,?>[] oldMap = table;
393
394
// overflow-conscious code
395
int newCapacity = (oldCapacity << 1) + 1;
396
if (newCapacity - MAX_ARRAY_SIZE > 0) {
397
if (oldCapacity == MAX_ARRAY_SIZE)
398
// Keep running with MAX_ARRAY_SIZE buckets
399
return;
400
newCapacity = MAX_ARRAY_SIZE;
401
}
402
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
403
404
modCount++;
405
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
406
table = newMap;
407
408
for (int i = oldCapacity ; i-- > 0 ;) {
409
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
410
Entry<K,V> e = old;
411
old = old.next;
412
413
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
414
e.next = (Entry<K,V>)newMap[index];
415
newMap[index] = e;
416
}
417
}
418
}
419
420
private void addEntry(int hash, K key, V value, int index) {
421
modCount++;
422
423
Entry<?,?> tab[] = table;
424
if (count >= threshold) {
425
// Rehash the table if the threshold is exceeded
426
rehash();
427
428
tab = table;
429
hash = key.hashCode();
430
index = (hash & 0x7FFFFFFF) % tab.length;
431
}
432
433
// Creates the new entry.
434
@SuppressWarnings("unchecked")
435
Entry<K,V> e = (Entry<K,V>) tab[index];
436
tab[index] = new Entry<>(hash, key, value, e);
437
count++;
438
}
439
440
/**
441
* Maps the specified <code>key</code> to the specified
442
* <code>value</code> in this hashtable. Neither the key nor the
443
* value can be <code>null</code>. <p>
444
*
445
* The value can be retrieved by calling the <code>get</code> method
446
* with a key that is equal to the original key.
447
*
448
* @param key the hashtable key
449
* @param value the value
450
* @return the previous value of the specified key in this hashtable,
451
* or <code>null</code> if it did not have one
452
* @exception NullPointerException if the key or value is
453
* <code>null</code>
454
* @see Object#equals(Object)
455
* @see #get(Object)
456
*/
457
public synchronized V put(K key, V value) {
458
// Make sure the value is not null
459
if (value == null) {
460
throw new NullPointerException();
461
}
462
463
// Makes sure the key is not already in the hashtable.
464
Entry<?,?> tab[] = table;
465
int hash = key.hashCode();
466
int index = (hash & 0x7FFFFFFF) % tab.length;
467
@SuppressWarnings("unchecked")
468
Entry<K,V> entry = (Entry<K,V>)tab[index];
469
for(; entry != null ; entry = entry.next) {
470
if ((entry.hash == hash) && entry.key.equals(key)) {
471
V old = entry.value;
472
entry.value = value;
473
return old;
474
}
475
}
476
477
addEntry(hash, key, value, index);
478
return null;
479
}
480
481
/**
482
* Removes the key (and its corresponding value) from this
483
* hashtable. This method does nothing if the key is not in the hashtable.
484
*
485
* @param key the key that needs to be removed
486
* @return the value to which the key had been mapped in this hashtable,
487
* or <code>null</code> if the key did not have a mapping
488
* @throws NullPointerException if the key is <code>null</code>
489
*/
490
public synchronized V remove(Object key) {
491
Entry<?,?> tab[] = table;
492
int hash = key.hashCode();
493
int index = (hash & 0x7FFFFFFF) % tab.length;
494
@SuppressWarnings("unchecked")
495
Entry<K,V> e = (Entry<K,V>)tab[index];
496
for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
497
if ((e.hash == hash) && e.key.equals(key)) {
498
modCount++;
499
if (prev != null) {
500
prev.next = e.next;
501
} else {
502
tab[index] = e.next;
503
}
504
count--;
505
V oldValue = e.value;
506
e.value = null;
507
return oldValue;
508
}
509
}
510
return null;
511
}
512
513
/**
514
* Copies all of the mappings from the specified map to this hashtable.
515
* These mappings will replace any mappings that this hashtable had for any
516
* of the keys currently in the specified map.
517
*
518
* @param t mappings to be stored in this map
519
* @throws NullPointerException if the specified map is null
520
* @since 1.2
521
*/
522
public synchronized void putAll(Map<? extends K, ? extends V> t) {
523
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
524
put(e.getKey(), e.getValue());
525
}
526
527
/**
528
* Clears this hashtable so that it contains no keys.
529
*/
530
public synchronized void clear() {
531
Entry<?,?> tab[] = table;
532
modCount++;
533
for (int index = tab.length; --index >= 0; )
534
tab[index] = null;
535
count = 0;
536
}
537
538
/**
539
* Creates a shallow copy of this hashtable. All the structure of the
540
* hashtable itself is copied, but the keys and values are not cloned.
541
* This is a relatively expensive operation.
542
*
543
* @return a clone of the hashtable
544
*/
545
public synchronized Object clone() {
546
try {
547
Hashtable<?,?> t = (Hashtable<?,?>)super.clone();
548
t.table = new Entry<?,?>[table.length];
549
for (int i = table.length ; i-- > 0 ; ) {
550
t.table[i] = (table[i] != null)
551
? (Entry<?,?>) table[i].clone() : null;
552
}
553
t.keySet = null;
554
t.entrySet = null;
555
t.values = null;
556
t.modCount = 0;
557
return t;
558
} catch (CloneNotSupportedException e) {
559
// this shouldn't happen, since we are Cloneable
560
throw new InternalError(e);
561
}
562
}
563
564
/**
565
* Returns a string representation of this <tt>Hashtable</tt> object
566
* in the form of a set of entries, enclosed in braces and separated
567
* by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
568
* entry is rendered as the key, an equals sign <tt>=</tt>, and the
569
* associated element, where the <tt>toString</tt> method is used to
570
* convert the key and element to strings.
571
*
572
* @return a string representation of this hashtable
573
*/
574
public synchronized String toString() {
575
int max = size() - 1;
576
if (max == -1)
577
return "{}";
578
579
StringBuilder sb = new StringBuilder();
580
Iterator<Map.Entry<K,V>> it = entrySet().iterator();
581
582
sb.append('{');
583
for (int i = 0; ; i++) {
584
Map.Entry<K,V> e = it.next();
585
K key = e.getKey();
586
V value = e.getValue();
587
sb.append(key == this ? "(this Map)" : key.toString());
588
sb.append('=');
589
sb.append(value == this ? "(this Map)" : value.toString());
590
591
if (i == max)
592
return sb.append('}').toString();
593
sb.append(", ");
594
}
595
}
596
597
598
private <T> Enumeration<T> getEnumeration(int type) {
599
if (count == 0) {
600
return Collections.emptyEnumeration();
601
} else {
602
return new Enumerator<>(type, false);
603
}
604
}
605
606
private <T> Iterator<T> getIterator(int type) {
607
if (count == 0) {
608
return Collections.emptyIterator();
609
} else {
610
return new Enumerator<>(type, true);
611
}
612
}
613
614
// Views
615
616
/**
617
* Each of these fields are initialized to contain an instance of the
618
* appropriate view the first time this view is requested. The views are
619
* stateless, so there's no reason to create more than one of each.
620
*/
621
private transient volatile Set<K> keySet;
622
private transient volatile Set<Map.Entry<K,V>> entrySet;
623
private transient volatile Collection<V> values;
624
625
/**
626
* Returns a {@link Set} view of the keys contained in this map.
627
* The set is backed by the map, so changes to the map are
628
* reflected in the set, and vice-versa. If the map is modified
629
* while an iteration over the set is in progress (except through
630
* the iterator's own <tt>remove</tt> operation), the results of
631
* the iteration are undefined. The set supports element removal,
632
* which removes the corresponding mapping from the map, via the
633
* <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
634
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
635
* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
636
* operations.
637
*
638
* @since 1.2
639
*/
640
public Set<K> keySet() {
641
if (keySet == null)
642
keySet = Collections.synchronizedSet(new KeySet(), this);
643
return keySet;
644
}
645
646
private class KeySet extends AbstractSet<K> {
647
public Iterator<K> iterator() {
648
return getIterator(KEYS);
649
}
650
public int size() {
651
return count;
652
}
653
public boolean contains(Object o) {
654
return containsKey(o);
655
}
656
public boolean remove(Object o) {
657
return Hashtable.this.remove(o) != null;
658
}
659
public void clear() {
660
Hashtable.this.clear();
661
}
662
}
663
664
/**
665
* Returns a {@link Set} view of the mappings contained in this map.
666
* The set is backed by the map, so changes to the map are
667
* reflected in the set, and vice-versa. If the map is modified
668
* while an iteration over the set is in progress (except through
669
* the iterator's own <tt>remove</tt> operation, or through the
670
* <tt>setValue</tt> operation on a map entry returned by the
671
* iterator) the results of the iteration are undefined. The set
672
* supports element removal, which removes the corresponding
673
* mapping from the map, via the <tt>Iterator.remove</tt>,
674
* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
675
* <tt>clear</tt> operations. It does not support the
676
* <tt>add</tt> or <tt>addAll</tt> operations.
677
*
678
* @since 1.2
679
*/
680
public Set<Map.Entry<K,V>> entrySet() {
681
if (entrySet==null)
682
entrySet = Collections.synchronizedSet(new EntrySet(), this);
683
return entrySet;
684
}
685
686
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
687
public Iterator<Map.Entry<K,V>> iterator() {
688
return getIterator(ENTRIES);
689
}
690
691
public boolean add(Map.Entry<K,V> o) {
692
return super.add(o);
693
}
694
695
public boolean contains(Object o) {
696
if (!(o instanceof Map.Entry))
697
return false;
698
Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
699
Object key = entry.getKey();
700
Entry<?,?>[] tab = table;
701
int hash = key.hashCode();
702
int index = (hash & 0x7FFFFFFF) % tab.length;
703
704
for (Entry<?,?> e = tab[index]; e != null; e = e.next)
705
if (e.hash==hash && e.equals(entry))
706
return true;
707
return false;
708
}
709
710
public boolean remove(Object o) {
711
if (!(o instanceof Map.Entry))
712
return false;
713
Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
714
Object key = entry.getKey();
715
Entry<?,?>[] tab = table;
716
int hash = key.hashCode();
717
int index = (hash & 0x7FFFFFFF) % tab.length;
718
719
@SuppressWarnings("unchecked")
720
Entry<K,V> e = (Entry<K,V>)tab[index];
721
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
722
if (e.hash==hash && e.equals(entry)) {
723
modCount++;
724
if (prev != null)
725
prev.next = e.next;
726
else
727
tab[index] = e.next;
728
729
count--;
730
e.value = null;
731
return true;
732
}
733
}
734
return false;
735
}
736
737
public int size() {
738
return count;
739
}
740
741
public void clear() {
742
Hashtable.this.clear();
743
}
744
}
745
746
/**
747
* Returns a {@link Collection} view of the values contained in this map.
748
* The collection is backed by the map, so changes to the map are
749
* reflected in the collection, and vice-versa. If the map is
750
* modified while an iteration over the collection is in progress
751
* (except through the iterator's own <tt>remove</tt> operation),
752
* the results of the iteration are undefined. The collection
753
* supports element removal, which removes the corresponding
754
* mapping from the map, via the <tt>Iterator.remove</tt>,
755
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
756
* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
757
* support the <tt>add</tt> or <tt>addAll</tt> operations.
758
*
759
* @since 1.2
760
*/
761
public Collection<V> values() {
762
if (values==null)
763
values = Collections.synchronizedCollection(new ValueCollection(),
764
this);
765
return values;
766
}
767
768
private class ValueCollection extends AbstractCollection<V> {
769
public Iterator<V> iterator() {
770
return getIterator(VALUES);
771
}
772
public int size() {
773
return count;
774
}
775
public boolean contains(Object o) {
776
return containsValue(o);
777
}
778
public void clear() {
779
Hashtable.this.clear();
780
}
781
}
782
783
// Comparison and hashing
784
785
/**
786
* Compares the specified Object with this Map for equality,
787
* as per the definition in the Map interface.
788
*
789
* @param o object to be compared for equality with this hashtable
790
* @return true if the specified Object is equal to this Map
791
* @see Map#equals(Object)
792
* @since 1.2
793
*/
794
public synchronized boolean equals(Object o) {
795
if (o == this)
796
return true;
797
798
if (!(o instanceof Map))
799
return false;
800
Map<?,?> t = (Map<?,?>) o;
801
if (t.size() != size())
802
return false;
803
804
try {
805
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
806
while (i.hasNext()) {
807
Map.Entry<K,V> e = i.next();
808
K key = e.getKey();
809
V value = e.getValue();
810
if (value == null) {
811
if (!(t.get(key)==null && t.containsKey(key)))
812
return false;
813
} else {
814
if (!value.equals(t.get(key)))
815
return false;
816
}
817
}
818
} catch (ClassCastException unused) {
819
return false;
820
} catch (NullPointerException unused) {
821
return false;
822
}
823
824
return true;
825
}
826
827
/**
828
* Returns the hash code value for this Map as per the definition in the
829
* Map interface.
830
*
831
* @see Map#hashCode()
832
* @since 1.2
833
*/
834
public synchronized int hashCode() {
835
/*
836
* This code detects the recursion caused by computing the hash code
837
* of a self-referential hash table and prevents the stack overflow
838
* that would otherwise result. This allows certain 1.1-era
839
* applets with self-referential hash tables to work. This code
840
* abuses the loadFactor field to do double-duty as a hashCode
841
* in progress flag, so as not to worsen the space performance.
842
* A negative load factor indicates that hash code computation is
843
* in progress.
844
*/
845
int h = 0;
846
if (count == 0 || loadFactor < 0)
847
return h; // Returns zero
848
849
loadFactor = -loadFactor; // Mark hashCode computation in progress
850
Entry<?,?>[] tab = table;
851
for (Entry<?,?> entry : tab) {
852
while (entry != null) {
853
h += entry.hashCode();
854
entry = entry.next;
855
}
856
}
857
858
loadFactor = -loadFactor; // Mark hashCode computation complete
859
860
return h;
861
}
862
863
@Override
864
public synchronized V getOrDefault(Object key, V defaultValue) {
865
V result = get(key);
866
return (null == result) ? defaultValue : result;
867
}
868
869
@SuppressWarnings("unchecked")
870
@Override
871
public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
872
Objects.requireNonNull(action); // explicit check required in case
873
// table is empty.
874
final int expectedModCount = modCount;
875
876
Entry<?, ?>[] tab = table;
877
for (Entry<?, ?> entry : tab) {
878
while (entry != null) {
879
action.accept((K)entry.key, (V)entry.value);
880
entry = entry.next;
881
882
if (expectedModCount != modCount) {
883
throw new ConcurrentModificationException();
884
}
885
}
886
}
887
}
888
889
@SuppressWarnings("unchecked")
890
@Override
891
public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
892
Objects.requireNonNull(function); // explicit check required in case
893
// table is empty.
894
final int expectedModCount = modCount;
895
896
Entry<K, V>[] tab = (Entry<K, V>[])table;
897
for (Entry<K, V> entry : tab) {
898
while (entry != null) {
899
entry.value = Objects.requireNonNull(
900
function.apply(entry.key, entry.value));
901
entry = entry.next;
902
903
if (expectedModCount != modCount) {
904
throw new ConcurrentModificationException();
905
}
906
}
907
}
908
}
909
910
@Override
911
public synchronized V putIfAbsent(K key, V value) {
912
Objects.requireNonNull(value);
913
914
// Makes sure the key is not already in the hashtable.
915
Entry<?,?> tab[] = table;
916
int hash = key.hashCode();
917
int index = (hash & 0x7FFFFFFF) % tab.length;
918
@SuppressWarnings("unchecked")
919
Entry<K,V> entry = (Entry<K,V>)tab[index];
920
for (; entry != null; entry = entry.next) {
921
if ((entry.hash == hash) && entry.key.equals(key)) {
922
V old = entry.value;
923
if (old == null) {
924
entry.value = value;
925
}
926
return old;
927
}
928
}
929
930
addEntry(hash, key, value, index);
931
return null;
932
}
933
934
@Override
935
public synchronized boolean remove(Object key, Object value) {
936
Objects.requireNonNull(value);
937
938
Entry<?,?> tab[] = table;
939
int hash = key.hashCode();
940
int index = (hash & 0x7FFFFFFF) % tab.length;
941
@SuppressWarnings("unchecked")
942
Entry<K,V> e = (Entry<K,V>)tab[index];
943
for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
944
if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
945
modCount++;
946
if (prev != null) {
947
prev.next = e.next;
948
} else {
949
tab[index] = e.next;
950
}
951
count--;
952
e.value = null;
953
return true;
954
}
955
}
956
return false;
957
}
958
959
@Override
960
public synchronized boolean replace(K key, V oldValue, V newValue) {
961
Objects.requireNonNull(oldValue);
962
Objects.requireNonNull(newValue);
963
Entry<?,?> tab[] = table;
964
int hash = key.hashCode();
965
int index = (hash & 0x7FFFFFFF) % tab.length;
966
@SuppressWarnings("unchecked")
967
Entry<K,V> e = (Entry<K,V>)tab[index];
968
for (; e != null; e = e.next) {
969
if ((e.hash == hash) && e.key.equals(key)) {
970
if (e.value.equals(oldValue)) {
971
e.value = newValue;
972
return true;
973
} else {
974
return false;
975
}
976
}
977
}
978
return false;
979
}
980
981
@Override
982
public synchronized V replace(K key, V value) {
983
Objects.requireNonNull(value);
984
Entry<?,?> tab[] = table;
985
int hash = key.hashCode();
986
int index = (hash & 0x7FFFFFFF) % tab.length;
987
@SuppressWarnings("unchecked")
988
Entry<K,V> e = (Entry<K,V>)tab[index];
989
for (; e != null; e = e.next) {
990
if ((e.hash == hash) && e.key.equals(key)) {
991
V oldValue = e.value;
992
e.value = value;
993
return oldValue;
994
}
995
}
996
return null;
997
}
998
999
@Override
1000
public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
1001
Objects.requireNonNull(mappingFunction);
1002
1003
Entry<?,?> tab[] = table;
1004
int hash = key.hashCode();
1005
int index = (hash & 0x7FFFFFFF) % tab.length;
1006
@SuppressWarnings("unchecked")
1007
Entry<K,V> e = (Entry<K,V>)tab[index];
1008
for (; e != null; e = e.next) {
1009
if (e.hash == hash && e.key.equals(key)) {
1010
// Hashtable not accept null value
1011
return e.value;
1012
}
1013
}
1014
1015
V newValue = mappingFunction.apply(key);
1016
if (newValue != null) {
1017
addEntry(hash, key, newValue, index);
1018
}
1019
1020
return newValue;
1021
}
1022
1023
@Override
1024
public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1025
Objects.requireNonNull(remappingFunction);
1026
1027
Entry<?,?> tab[] = table;
1028
int hash = key.hashCode();
1029
int index = (hash & 0x7FFFFFFF) % tab.length;
1030
@SuppressWarnings("unchecked")
1031
Entry<K,V> e = (Entry<K,V>)tab[index];
1032
for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1033
if (e.hash == hash && e.key.equals(key)) {
1034
V newValue = remappingFunction.apply(key, e.value);
1035
if (newValue == null) {
1036
modCount++;
1037
if (prev != null) {
1038
prev.next = e.next;
1039
} else {
1040
tab[index] = e.next;
1041
}
1042
count--;
1043
} else {
1044
e.value = newValue;
1045
}
1046
return newValue;
1047
}
1048
}
1049
return null;
1050
}
1051
1052
@Override
1053
public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1054
Objects.requireNonNull(remappingFunction);
1055
1056
Entry<?,?> tab[] = table;
1057
int hash = key.hashCode();
1058
int index = (hash & 0x7FFFFFFF) % tab.length;
1059
@SuppressWarnings("unchecked")
1060
Entry<K,V> e = (Entry<K,V>)tab[index];
1061
for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1062
if (e.hash == hash && Objects.equals(e.key, key)) {
1063
V newValue = remappingFunction.apply(key, e.value);
1064
if (newValue == null) {
1065
modCount++;
1066
if (prev != null) {
1067
prev.next = e.next;
1068
} else {
1069
tab[index] = e.next;
1070
}
1071
count--;
1072
} else {
1073
e.value = newValue;
1074
}
1075
return newValue;
1076
}
1077
}
1078
1079
V newValue = remappingFunction.apply(key, null);
1080
if (newValue != null) {
1081
addEntry(hash, key, newValue, index);
1082
}
1083
1084
return newValue;
1085
}
1086
1087
@Override
1088
public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1089
Objects.requireNonNull(remappingFunction);
1090
1091
Entry<?,?> tab[] = table;
1092
int hash = key.hashCode();
1093
int index = (hash & 0x7FFFFFFF) % tab.length;
1094
@SuppressWarnings("unchecked")
1095
Entry<K,V> e = (Entry<K,V>)tab[index];
1096
for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1097
if (e.hash == hash && e.key.equals(key)) {
1098
V newValue = remappingFunction.apply(e.value, value);
1099
if (newValue == null) {
1100
modCount++;
1101
if (prev != null) {
1102
prev.next = e.next;
1103
} else {
1104
tab[index] = e.next;
1105
}
1106
count--;
1107
} else {
1108
e.value = newValue;
1109
}
1110
return newValue;
1111
}
1112
}
1113
1114
if (value != null) {
1115
addEntry(hash, key, value, index);
1116
}
1117
1118
return value;
1119
}
1120
1121
/**
1122
* Save the state of the Hashtable to a stream (i.e., serialize it).
1123
*
1124
* @serialData The <i>capacity</i> of the Hashtable (the length of the
1125
* bucket array) is emitted (int), followed by the
1126
* <i>size</i> of the Hashtable (the number of key-value
1127
* mappings), followed by the key (Object) and value (Object)
1128
* for each key-value mapping represented by the Hashtable
1129
* The key-value mappings are emitted in no particular order.
1130
*/
1131
private void writeObject(java.io.ObjectOutputStream s)
1132
throws IOException {
1133
Entry<Object, Object> entryStack = null;
1134
1135
synchronized (this) {
1136
// Write out the threshold and loadFactor
1137
s.defaultWriteObject();
1138
1139
// Write out the length and count of elements
1140
s.writeInt(table.length);
1141
s.writeInt(count);
1142
1143
// Stack copies of the entries in the table
1144
for (int index = 0; index < table.length; index++) {
1145
Entry<?,?> entry = table[index];
1146
1147
while (entry != null) {
1148
entryStack =
1149
new Entry<>(0, entry.key, entry.value, entryStack);
1150
entry = entry.next;
1151
}
1152
}
1153
}
1154
1155
// Write out the key/value objects from the stacked entries
1156
while (entryStack != null) {
1157
s.writeObject(entryStack.key);
1158
s.writeObject(entryStack.value);
1159
entryStack = entryStack.next;
1160
}
1161
}
1162
1163
/**
1164
* Reconstitute the Hashtable from a stream (i.e., deserialize it).
1165
*/
1166
private void readObject(java.io.ObjectInputStream s)
1167
throws IOException, ClassNotFoundException
1168
{
1169
// Read in the threshold and loadFactor
1170
s.defaultReadObject();
1171
1172
// Validate loadFactor (ignore threshold - it will be re-computed)
1173
if (loadFactor <= 0 || Float.isNaN(loadFactor))
1174
throw new StreamCorruptedException("Illegal Load: " + loadFactor);
1175
1176
// Read the original length of the array and number of elements
1177
int origlength = s.readInt();
1178
int elements = s.readInt();
1179
1180
// Validate # of elements
1181
if (elements < 0)
1182
throw new StreamCorruptedException("Illegal # of Elements: " + elements);
1183
1184
// Clamp original length to be more than elements / loadFactor
1185
// (this is the invariant enforced with auto-growth)
1186
origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
1187
1188
// Compute new length with a bit of room 5% + 3 to grow but
1189
// no larger than the clamped original length. Make the length
1190
// odd if it's large enough, this helps distribute the entries.
1191
// Guard against the length ending up zero, that's not valid.
1192
int length = (int)((elements + elements / 20) / loadFactor) + 3;
1193
if (length > elements && (length & 1) == 0)
1194
length--;
1195
length = Math.min(length, origlength);
1196
1197
if (length < 0) { // overflow
1198
length = origlength;
1199
}
1200
1201
// Check Map.Entry[].class since it's the nearest public type to
1202
// what we're actually creating.
1203
SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
1204
table = new Entry<?,?>[length];
1205
threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1206
count = 0;
1207
1208
// Read the number of elements and then all the key/value objects
1209
for (; elements > 0; elements--) {
1210
@SuppressWarnings("unchecked")
1211
K key = (K)s.readObject();
1212
@SuppressWarnings("unchecked")
1213
V value = (V)s.readObject();
1214
// sync is eliminated for performance
1215
reconstitutionPut(table, key, value);
1216
}
1217
}
1218
1219
/**
1220
* The put method used by readObject. This is provided because put
1221
* is overridable and should not be called in readObject since the
1222
* subclass will not yet be initialized.
1223
*
1224
* <p>This differs from the regular put method in several ways. No
1225
* checking for rehashing is necessary since the number of elements
1226
* initially in the table is known. The modCount is not incremented and
1227
* there's no synchronization because we are creating a new instance.
1228
* Also, no return value is needed.
1229
*/
1230
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
1231
throws StreamCorruptedException
1232
{
1233
if (value == null) {
1234
throw new java.io.StreamCorruptedException();
1235
}
1236
// Makes sure the key is not already in the hashtable.
1237
// This should not happen in deserialized version.
1238
int hash = key.hashCode();
1239
int index = (hash & 0x7FFFFFFF) % tab.length;
1240
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
1241
if ((e.hash == hash) && e.key.equals(key)) {
1242
throw new java.io.StreamCorruptedException();
1243
}
1244
}
1245
// Creates the new entry.
1246
@SuppressWarnings("unchecked")
1247
Entry<K,V> e = (Entry<K,V>)tab[index];
1248
tab[index] = new Entry<>(hash, key, value, e);
1249
count++;
1250
}
1251
1252
/**
1253
* Hashtable bucket collision list entry
1254
*/
1255
private static class Entry<K,V> implements Map.Entry<K,V> {
1256
final int hash;
1257
final K key;
1258
V value;
1259
Entry<K,V> next;
1260
1261
protected Entry(int hash, K key, V value, Entry<K,V> next) {
1262
this.hash = hash;
1263
this.key = key;
1264
this.value = value;
1265
this.next = next;
1266
}
1267
1268
@SuppressWarnings("unchecked")
1269
protected Object clone() {
1270
return new Entry<>(hash, key, value,
1271
(next==null ? null : (Entry<K,V>) next.clone()));
1272
}
1273
1274
// Map.Entry Ops
1275
1276
public K getKey() {
1277
return key;
1278
}
1279
1280
public V getValue() {
1281
return value;
1282
}
1283
1284
public V setValue(V value) {
1285
if (value == null)
1286
throw new NullPointerException();
1287
1288
V oldValue = this.value;
1289
this.value = value;
1290
return oldValue;
1291
}
1292
1293
public boolean equals(Object o) {
1294
if (!(o instanceof Map.Entry))
1295
return false;
1296
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1297
1298
return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
1299
(value==null ? e.getValue()==null : value.equals(e.getValue()));
1300
}
1301
1302
public int hashCode() {
1303
return hash ^ Objects.hashCode(value);
1304
}
1305
1306
public String toString() {
1307
return key.toString()+"="+value.toString();
1308
}
1309
}
1310
1311
// Types of Enumerations/Iterations
1312
private static final int KEYS = 0;
1313
private static final int VALUES = 1;
1314
private static final int ENTRIES = 2;
1315
1316
/**
1317
* A hashtable enumerator class. This class implements both the
1318
* Enumeration and Iterator interfaces, but individual instances
1319
* can be created with the Iterator methods disabled. This is necessary
1320
* to avoid unintentionally increasing the capabilities granted a user
1321
* by passing an Enumeration.
1322
*/
1323
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
1324
Entry<?,?>[] table = Hashtable.this.table;
1325
int index = table.length;
1326
Entry<?,?> entry;
1327
Entry<?,?> lastReturned;
1328
int type;
1329
1330
/**
1331
* Indicates whether this Enumerator is serving as an Iterator
1332
* or an Enumeration. (true -> Iterator).
1333
*/
1334
boolean iterator;
1335
1336
/**
1337
* The modCount value that the iterator believes that the backing
1338
* Hashtable should have. If this expectation is violated, the iterator
1339
* has detected concurrent modification.
1340
*/
1341
protected int expectedModCount = modCount;
1342
1343
Enumerator(int type, boolean iterator) {
1344
this.type = type;
1345
this.iterator = iterator;
1346
}
1347
1348
public boolean hasMoreElements() {
1349
Entry<?,?> e = entry;
1350
int i = index;
1351
Entry<?,?>[] t = table;
1352
/* Use locals for faster loop iteration */
1353
while (e == null && i > 0) {
1354
e = t[--i];
1355
}
1356
entry = e;
1357
index = i;
1358
return e != null;
1359
}
1360
1361
@SuppressWarnings("unchecked")
1362
public T nextElement() {
1363
Entry<?,?> et = entry;
1364
int i = index;
1365
Entry<?,?>[] t = table;
1366
/* Use locals for faster loop iteration */
1367
while (et == null && i > 0) {
1368
et = t[--i];
1369
}
1370
entry = et;
1371
index = i;
1372
if (et != null) {
1373
Entry<?,?> e = lastReturned = entry;
1374
entry = e.next;
1375
return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
1376
}
1377
throw new NoSuchElementException("Hashtable Enumerator");
1378
}
1379
1380
// Iterator methods
1381
public boolean hasNext() {
1382
return hasMoreElements();
1383
}
1384
1385
public T next() {
1386
if (modCount != expectedModCount)
1387
throw new ConcurrentModificationException();
1388
return nextElement();
1389
}
1390
1391
public void remove() {
1392
if (!iterator)
1393
throw new UnsupportedOperationException();
1394
if (lastReturned == null)
1395
throw new IllegalStateException("Hashtable Enumerator");
1396
if (modCount != expectedModCount)
1397
throw new ConcurrentModificationException();
1398
1399
synchronized(Hashtable.this) {
1400
Entry<?,?>[] tab = Hashtable.this.table;
1401
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
1402
1403
@SuppressWarnings("unchecked")
1404
Entry<K,V> e = (Entry<K,V>)tab[index];
1405
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1406
if (e == lastReturned) {
1407
modCount++;
1408
expectedModCount++;
1409
if (prev == null)
1410
tab[index] = e.next;
1411
else
1412
prev.next = e.next;
1413
count--;
1414
lastReturned = null;
1415
return;
1416
}
1417
}
1418
throw new ConcurrentModificationException();
1419
}
1420
}
1421
}
1422
}
1423
1424