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