History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/EnumMap.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/EnumMap.java+799−0
@@ -0,0 +1,799 @@
1/*
2 * Copyright (c) 2003, 2010, 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
26package java.util;
27
28import java.util.Map.Entry;
29import sun.misc.SharedSecrets;
30
31/**
32 * A specialized {@link Map} implementation for use with enum type keys. All
33 * of the keys in an enum map must come from a single enum type that is
34 * specified, explicitly or implicitly, when the map is created. Enum maps
35 * are represented internally as arrays. This representation is extremely
36 * compact and efficient.
37 *
38 * <p>Enum maps are maintained in the <i>natural order</i> of their keys
39 * (the order in which the enum constants are declared). This is reflected
40 * in the iterators returned by the collections views ({@link #keySet()},
41 * {@link #entrySet()}, and {@link #values()}).
42 *
43 * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
44 * they will never throw {@link ConcurrentModificationException} and they may
45 * or may not show the effects of any modifications to the map that occur while
46 * the iteration is in progress.
47 *
48 * <p>Null keys are not permitted. Attempts to insert a null key will
49 * throw {@link NullPointerException}. Attempts to test for the
50 * presence of a null key or to remove one will, however, function properly.
51 * Null values are permitted.
52
53 * <P>Like most collection implementations <tt>EnumMap</tt> is not
54 * synchronized. If multiple threads access an enum map concurrently, and at
55 * least one of the threads modifies the map, it should be synchronized
56 * externally. This is typically accomplished by synchronizing on some
57 * object that naturally encapsulates the enum map. If no such object exists,
58 * the map should be "wrapped" using the {@link Collections#synchronizedMap}
59 * method. This is best done at creation time, to prevent accidental
60 * unsynchronized access:
61 *
62 * <pre>
63 * Map&lt;EnumKey, V&gt; m
64 * = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
65 * </pre>
66 *
67 * <p>Implementation note: All basic operations execute in constant time.
68 * They are likely (though not guaranteed) to be faster than their
69 * {@link HashMap} counterparts.
70 *
71 * <p>This class is a member of the
72 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
73 * Java Collections Framework</a>.
74 *
75 * @author Josh Bloch
76 * @see EnumSet
77 * @since 1.5
78 */
79public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
80 implements java.io.Serializable, Cloneable
81{
82 /**
83 * The <tt>Class</tt> object for the enum type of all the keys of this map.
84 *
85 * @serial
86 */
87 private final Class<K> keyType;
88
89 /**
90 * All of the values comprising K. (Cached for performance.)
91 */
92 private transient K[] keyUniverse;
93
94 /**
95 * Array representation of this map. The ith element is the value
96 * to which universe[i] is currently mapped, or null if it isn't
97 * mapped to anything, or NULL if it's mapped to null.
98 */
99 private transient Object[] vals;
100
101 /**
102 * The number of mappings in this map.
103 */
104 private transient int size = 0;
105
106 /**
107 * Distinguished non-null value for representing null values.
108 */
109 private static final Object NULL = new Integer(0);
110
111 private Object maskNull(Object value) {
112 return (value == null ? NULL : value);
113 }
114
115 private V unmaskNull(Object value) {
116 return (V) (value == NULL ? null : value);
117 }
118
119 private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
120
121 /**
122 * Creates an empty enum map with the specified key type.
123 *
124 * @param keyType the class object of the key type for this enum map
125 * @throws NullPointerException if <tt>keyType</tt> is null
126 */
127 public EnumMap(Class<K> keyType) {
128 this.keyType = keyType;
129 keyUniverse = getKeyUniverse(keyType);
130 vals = new Object[keyUniverse.length];
131 }
132
133 /**
134 * Creates an enum map with the same key type as the specified enum
135 * map, initially containing the same mappings (if any).
136 *
137 * @param m the enum map from which to initialize this enum map
138 * @throws NullPointerException if <tt>m</tt> is null
139 */
140 public EnumMap(EnumMap<K, ? extends V> m) {
141 keyType = m.keyType;
142 keyUniverse = m.keyUniverse;
143 vals = m.vals.clone();
144 size = m.size;
145 }
146
147 /**
148 * Creates an enum map initialized from the specified map. If the
149 * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
150 * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map
151 * must contain at least one mapping (in order to determine the new
152 * enum map's key type).
153 *
154 * @param m the map from which to initialize this enum map
155 * @throws IllegalArgumentException if <tt>m</tt> is not an
156 * <tt>EnumMap</tt> instance and contains no mappings
157 * @throws NullPointerException if <tt>m</tt> is null
158 */
159 public EnumMap(Map<K, ? extends V> m) {
160 if (m instanceof EnumMap) {
161 EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
162 keyType = em.keyType;
163 keyUniverse = em.keyUniverse;
164 vals = em.vals.clone();
165 size = em.size;
166 } else {
167 if (m.isEmpty())
168 throw new IllegalArgumentException("Specified map is empty");
169 keyType = m.keySet().iterator().next().getDeclaringClass();
170 keyUniverse = getKeyUniverse(keyType);
171 vals = new Object[keyUniverse.length];
172 putAll(m);
173 }
174 }
175
176 // Query Operations
177
178 /**
179 * Returns the number of key-value mappings in this map.
180 *
181 * @return the number of key-value mappings in this map
182 */
183 public int size() {
184 return size;
185 }
186
187 /**
188 * Returns <tt>true</tt> if this map maps one or more keys to the
189 * specified value.
190 *
191 * @param value the value whose presence in this map is to be tested
192 * @return <tt>true</tt> if this map maps one or more keys to this value
193 */
194 public boolean containsValue(Object value) {
195 value = maskNull(value);
196
197 for (Object val : vals)
198 if (value.equals(val))
199 return true;
200
201 return false;
202 }
203
204 /**
205 * Returns <tt>true</tt> if this map contains a mapping for the specified
206 * key.
207 *
208 * @param key the key whose presence in this map is to be tested
209 * @return <tt>true</tt> if this map contains a mapping for the specified
210 * key
211 */
212 public boolean containsKey(Object key) {
213 return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
214 }
215
216 private boolean containsMapping(Object key, Object value) {
217 return isValidKey(key) &&
218 maskNull(value).equals(vals[((Enum)key).ordinal()]);
219 }
220
221 /**
222 * Returns the value to which the specified key is mapped,
223 * or {@code null} if this map contains no mapping for the key.
224 *
225 * <p>More formally, if this map contains a mapping from a key
226 * {@code k} to a value {@code v} such that {@code (key == k)},
227 * then this method returns {@code v}; otherwise it returns
228 * {@code null}. (There can be at most one such mapping.)
229 *
230 * <p>A return value of {@code null} does not <i>necessarily</i>
231 * indicate that the map contains no mapping for the key; it's also
232 * possible that the map explicitly maps the key to {@code null}.
233 * The {@link #containsKey containsKey} operation may be used to
234 * distinguish these two cases.
235 */
236 public V get(Object key) {
237 return (isValidKey(key) ?
238 unmaskNull(vals[((Enum)key).ordinal()]) : null);
239 }
240
241 // Modification Operations
242
243 /**
244 * Associates the specified value with the specified key in this map.
245 * If the map previously contained a mapping for this key, the old
246 * value is replaced.
247 *
248 * @param key the key with which the specified value is to be associated
249 * @param value the value to be associated with the specified key
250 *
251 * @return the previous value associated with specified key, or
252 * <tt>null</tt> if there was no mapping for key. (A <tt>null</tt>
253 * return can also indicate that the map previously associated
254 * <tt>null</tt> with the specified key.)
255 * @throws NullPointerException if the specified key is null
256 */
257 public V put(K key, V value) {
258 typeCheck(key);
259
260 int index = key.ordinal();
261 Object oldValue = vals[index];
262 vals[index] = maskNull(value);
263 if (oldValue == null)
264 size++;
265 return unmaskNull(oldValue);
266 }
267
268 /**
269 * Removes the mapping for this key from this map if present.
270 *
271 * @param key the key whose mapping is to be removed from the map
272 * @return the previous value associated with specified key, or
273 * <tt>null</tt> if there was no entry for key. (A <tt>null</tt>
274 * return can also indicate that the map previously associated
275 * <tt>null</tt> with the specified key.)
276 */
277 public V remove(Object key) {
278 if (!isValidKey(key))
279 return null;
280 int index = ((Enum)key).ordinal();
281 Object oldValue = vals[index];
282 vals[index] = null;
283 if (oldValue != null)
284 size--;
285 return unmaskNull(oldValue);
286 }
287
288 private boolean removeMapping(Object key, Object value) {
289 if (!isValidKey(key))
290 return false;
291 int index = ((Enum)key).ordinal();
292 if (maskNull(value).equals(vals[index])) {
293 vals[index] = null;
294 size--;
295 return true;
296 }
297 return false;
298 }
299
300 /**
301 * Returns true if key is of the proper type to be a key in this
302 * enum map.
303 */
304 private boolean isValidKey(Object key) {
305 if (key == null)
306 return false;
307
308 // Cheaper than instanceof Enum followed by getDeclaringClass
309 Class keyClass = key.getClass();
310 return keyClass == keyType || keyClass.getSuperclass() == keyType;
311 }
312
313 // Bulk Operations
314
315 /**
316 * Copies all of the mappings from the specified map to this map.
317 * These mappings will replace any mappings that this map had for
318 * any of the keys currently in the specified map.
319 *
320 * @param m the mappings to be stored in this map
321 * @throws NullPointerException the specified map is null, or if
322 * one or more keys in the specified map are null
323 */
324 public void putAll(Map<? extends K, ? extends V> m) {
325 if (m instanceof EnumMap) {
326 EnumMap<? extends K, ? extends V> em =
327 (EnumMap<? extends K, ? extends V>)m;
328 if (em.keyType != keyType) {
329 if (em.isEmpty())
330 return;
331 throw new ClassCastException(em.keyType + " != " + keyType);
332 }
333
334 for (int i = 0; i < keyUniverse.length; i++) {
335 Object emValue = em.vals[i];
336 if (emValue != null) {
337 if (vals[i] == null)
338 size++;
339 vals[i] = emValue;
340 }
341 }
342 } else {
343 super.putAll(m);
344 }
345 }
346
347 /**
348 * Removes all mappings from this map.
349 */
350 public void clear() {
351 Arrays.fill(vals, null);
352 size = 0;
353 }
354
355 // Views
356
357 /**
358 * This field is initialized to contain an instance of the entry set
359 * view the first time this view is requested. The view is stateless,
360 * so there's no reason to create more than one.
361 */
362 private transient Set<Map.Entry<K,V>> entrySet = null;
363
364 /**
365 * Returns a {@link Set} view of the keys contained in this map.
366 * The returned set obeys the general contract outlined in
367 * {@link Map#keySet()}. The set's iterator will return the keys
368 * in their natural order (the order in which the enum constants
369 * are declared).
370 *
371 * @return a set view of the keys contained in this enum map
372 */
373 public Set<K> keySet() {
374 Set<K> ks = keySet;
375 if (ks != null)
376 return ks;
377 else
378 return keySet = new KeySet();
379 }
380
381 private class KeySet extends AbstractSet<K> {
382 public Iterator<K> iterator() {
383 return new KeyIterator();
384 }
385 public int size() {
386 return size;
387 }
388 public boolean contains(Object o) {
389 return containsKey(o);
390 }
391 public boolean remove(Object o) {
392 int oldSize = size;
393 EnumMap.this.remove(o);
394 return size != oldSize;
395 }
396 public void clear() {
397 EnumMap.this.clear();
398 }
399 }
400
401 /**
402 * Returns a {@link Collection} view of the values contained in this map.
403 * The returned collection obeys the general contract outlined in
404 * {@link Map#values()}. The collection's iterator will return the
405 * values in the order their corresponding keys appear in map,
406 * which is their natural order (the order in which the enum constants
407 * are declared).
408 *
409 * @return a collection view of the values contained in this map
410 */
411 public Collection<V> values() {
412 Collection<V> vs = values;
413 if (vs != null)
414 return vs;
415 else
416 return values = new Values();
417 }
418
419 private class Values extends AbstractCollection<V> {
420 public Iterator<V> iterator() {
421 return new ValueIterator();
422 }
423 public int size() {
424 return size;
425 }
426 public boolean contains(Object o) {
427 return containsValue(o);
428 }
429 public boolean remove(Object o) {
430 o = maskNull(o);
431
432 for (int i = 0; i < vals.length; i++) {
433 if (o.equals(vals[i])) {
434 vals[i] = null;
435 size--;
436 return true;
437 }
438 }
439 return false;
440 }
441 public void clear() {
442 EnumMap.this.clear();
443 }
444 }
445
446 /**
447 * Returns a {@link Set} view of the mappings contained in this map.
448 * The returned set obeys the general contract outlined in
449 * {@link Map#keySet()}. The set's iterator will return the
450 * mappings in the order their keys appear in map, which is their
451 * natural order (the order in which the enum constants are declared).
452 *
453 * @return a set view of the mappings contained in this enum map
454 */
455 public Set<Map.Entry<K,V>> entrySet() {
456 Set<Map.Entry<K,V>> es = entrySet;
457 if (es != null)
458 return es;
459 else
460 return entrySet = new EntrySet();
461 }
462
463 private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
464 public Iterator<Map.Entry<K,V>> iterator() {
465 return new EntryIterator();
466 }
467
468 public boolean contains(Object o) {
469 if (!(o instanceof Map.Entry))
470 return false;
471 Map.Entry entry = (Map.Entry)o;
472 return containsMapping(entry.getKey(), entry.getValue());
473 }
474 public boolean remove(Object o) {
475 if (!(o instanceof Map.Entry))
476 return false;
477 Map.Entry entry = (Map.Entry)o;
478 return removeMapping(entry.getKey(), entry.getValue());
479 }
480 public int size() {
481 return size;
482 }
483 public void clear() {
484 EnumMap.this.clear();
485 }
486 public Object[] toArray() {
487 return fillEntryArray(new Object[size]);
488 }
489 @SuppressWarnings("unchecked")
490 public <T> T[] toArray(T[] a) {
491 int size = size();
492 if (a.length < size)
493 a = (T[])java.lang.reflect.Array
494 .newInstance(a.getClass().getComponentType(), size);
495 if (a.length > size)
496 a[size] = null;
497 return (T[]) fillEntryArray(a);
498 }
499 private Object[] fillEntryArray(Object[] a) {
500 int j = 0;
501 for (int i = 0; i < vals.length; i++)
502 if (vals[i] != null)
503 a[j++] = new AbstractMap.SimpleEntry<>(
504 keyUniverse[i], unmaskNull(vals[i]));
505 return a;
506 }
507 }
508
509 private abstract class EnumMapIterator<T> implements Iterator<T> {
510 // Lower bound on index of next element to return
511 int index = 0;
512
513 // Index of last returned element, or -1 if none
514 int lastReturnedIndex = -1;
515
516 public boolean hasNext() {
517 while (index < vals.length && vals[index] == null)
518 index++;
519 return index != vals.length;
520 }
521
522 public void remove() {
523 checkLastReturnedIndex();
524
525 if (vals[lastReturnedIndex] != null) {
526 vals[lastReturnedIndex] = null;
527 size--;
528 }
529 lastReturnedIndex = -1;
530 }
531
532 private void checkLastReturnedIndex() {
533 if (lastReturnedIndex < 0)
534 throw new IllegalStateException();
535 }
536 }
537
538 private class KeyIterator extends EnumMapIterator<K> {
539 public K next() {
540 if (!hasNext())
541 throw new NoSuchElementException();
542 lastReturnedIndex = index++;
543 return keyUniverse[lastReturnedIndex];
544 }
545 }
546
547 private class ValueIterator extends EnumMapIterator<V> {
548 public V next() {
549 if (!hasNext())
550 throw new NoSuchElementException();
551 lastReturnedIndex = index++;
552 return unmaskNull(vals[lastReturnedIndex]);
553 }
554 }
555
556 private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
557 private Entry lastReturnedEntry = null;
558
559 public Map.Entry<K,V> next() {
560 if (!hasNext())
561 throw new NoSuchElementException();
562 lastReturnedEntry = new Entry(index++);
563 return lastReturnedEntry;
564 }
565
566 public void remove() {
567 lastReturnedIndex =
568 ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
569 super.remove();
570 lastReturnedEntry.index = lastReturnedIndex;
571 lastReturnedEntry = null;
572 }
573
574 private class Entry implements Map.Entry<K,V> {
575 private int index;
576
577 private Entry(int index) {
578 this.index = index;
579 }
580
581 public K getKey() {
582 checkIndexForEntryUse();
583 return keyUniverse[index];
584 }
585
586 public V getValue() {
587 checkIndexForEntryUse();
588 return unmaskNull(vals[index]);
589 }
590
591 public V setValue(V value) {
592 checkIndexForEntryUse();
593 V oldValue = unmaskNull(vals[index]);
594 vals[index] = maskNull(value);
595 return oldValue;
596 }
597
598 public boolean equals(Object o) {
599 if (index < 0)
600 return o == this;
601
602 if (!(o instanceof Map.Entry))
603 return false;
604
605 Map.Entry e = (Map.Entry)o;
606 V ourValue = unmaskNull(vals[index]);
607 Object hisValue = e.getValue();
608 return (e.getKey() == keyUniverse[index] &&
609 (ourValue == hisValue ||
610 (ourValue != null && ourValue.equals(hisValue))));
611 }
612
613 public int hashCode() {
614 if (index < 0)
615 return super.hashCode();
616
617 return entryHashCode(index);
618 }
619
620 public String toString() {
621 if (index < 0)
622 return super.toString();
623
624 return keyUniverse[index] + "="
625 + unmaskNull(vals[index]);
626 }
627
628 private void checkIndexForEntryUse() {
629 if (index < 0)
630 throw new IllegalStateException("Entry was removed");
631 }
632 }
633 }
634
635 // Comparison and hashing
636
637 /**
638 * Compares the specified object with this map for equality. Returns
639 * <tt>true</tt> if the given object is also a map and the two maps
640 * represent the same mappings, as specified in the {@link
641 * Map#equals(Object)} contract.
642 *
643 * @param o the object to be compared for equality with this map
644 * @return <tt>true</tt> if the specified object is equal to this map
645 */
646 public boolean equals(Object o) {
647 if (this == o)
648 return true;
649 if (o instanceof EnumMap)
650 return equals((EnumMap)o);
651 if (!(o instanceof Map))
652 return false;
653
654 Map<K,V> m = (Map<K,V>)o;
655 if (size != m.size())
656 return false;
657
658 for (int i = 0; i < keyUniverse.length; i++) {
659 if (null != vals[i]) {
660 K key = keyUniverse[i];
661 V value = unmaskNull(vals[i]);
662 if (null == value) {
663 if (!((null == m.get(key)) && m.containsKey(key)))
664 return false;
665 } else {
666 if (!value.equals(m.get(key)))
667 return false;
668 }
669 }
670 }
671
672 return true;
673 }
674
675 private boolean equals(EnumMap em) {
676 if (em.keyType != keyType)
677 return size == 0 && em.size == 0;
678
679 // Key types match, compare each value
680 for (int i = 0; i < keyUniverse.length; i++) {
681 Object ourValue = vals[i];
682 Object hisValue = em.vals[i];
683 if (hisValue != ourValue &&
684 (hisValue == null || !hisValue.equals(ourValue)))
685 return false;
686 }
687 return true;
688 }
689
690 /**
691 * Returns the hash code value for this map. The hash code of a map is
692 * defined to be the sum of the hash codes of each entry in the map.
693 */
694 public int hashCode() {
695 int h = 0;
696
697 for (int i = 0; i < keyUniverse.length; i++) {
698 if (null != vals[i]) {
699 h += entryHashCode(i);
700 }
701 }
702
703 return h;
704 }
705
706 private int entryHashCode(int index) {
707 return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
708 }
709
710 /**
711 * Returns a shallow copy of this enum map. (The values themselves
712 * are not cloned.
713 *
714 * @return a shallow copy of this enum map
715 */
716 public EnumMap<K, V> clone() {
717 EnumMap<K, V> result = null;
718 try {
719 result = (EnumMap<K, V>) super.clone();
720 } catch(CloneNotSupportedException e) {
721 throw new AssertionError();
722 }
723 result.vals = result.vals.clone();
724 return result;
725 }
726
727 /**
728 * Throws an exception if e is not of the correct type for this enum set.
729 */
730 private void typeCheck(K key) {
731 Class keyClass = key.getClass();
732 if (keyClass != keyType && keyClass.getSuperclass() != keyType)
733 throw new ClassCastException(keyClass + " != " + keyType);
734 }
735
736 /**
737 * Returns all of the values comprising K.
738 * The result is uncloned, cached, and shared by all callers.
739 */
740 private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
741 return SharedSecrets.getJavaLangAccess()
742 .getEnumConstantsShared(keyType);
743 }
744
745 private static final long serialVersionUID = 458661240069192865L;
746
747 /**
748 * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
749 * serialize it).
750 *
751 * @serialData The <i>size</i> of the enum map (the number of key-value
752 * mappings) is emitted (int), followed by the key (Object)
753 * and value (Object) for each key-value mapping represented
754 * by the enum map.
755 */
756 private void writeObject(java.io.ObjectOutputStream s)
757 throws java.io.IOException
758 {
759 // Write out the key type and any hidden stuff
760 s.defaultWriteObject();
761
762 // Write out size (number of Mappings)
763 s.writeInt(size);
764
765 // Write out keys and values (alternating)
766 int entriesToBeWritten = size;
767 for (int i = 0; entriesToBeWritten > 0; i++) {
768 if (null != vals[i]) {
769 s.writeObject(keyUniverse[i]);
770 s.writeObject(unmaskNull(vals[i]));
771 entriesToBeWritten--;
772 }
773 }
774 }
775
776 /**
777 * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
778 * deserialize it).
779 */
780 private void readObject(java.io.ObjectInputStream s)
781 throws java.io.IOException, ClassNotFoundException
782 {
783 // Read in the key type and any hidden stuff
784 s.defaultReadObject();
785
786 keyUniverse = getKeyUniverse(keyType);
787 vals = new Object[keyUniverse.length];
788
789 // Read in size (number of Mappings)
790 int size = s.readInt();
791
792 // Read the keys and values, and put the mappings in the HashMap
793 for (int i = 0; i < size; i++) {
794 K key = (K) s.readObject();
795 V value = (V) s.readObject();
796 put(key, value);
797 }
798 }
799}