001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.Serializable;
024:
025: import org.apache.harmony.luni.internal.nls.Messages;
026:
027: /**
028: * Hashtable associates keys with values. Keys and values cannot be null. The
029: * size of the Hashtable is the number of key/value pairs it contains. The
030: * capacity is the number of key/value pairs the Hashtable can hold. The load
031: * factor is a float value which determines how full the Hashtable gets before
032: * expanding the capacity. If the load factor of the Hashtable is exceeded, the
033: * capacity is doubled.
034: *
035: * @see Enumeration
036: * @see java.io.Serializable
037: * @see java.lang.Object#equals
038: * @see java.lang.Object#hashCode
039: */
040:
041: public class Hashtable<K, V> extends Dictionary<K, V> implements
042: Map<K, V>, Cloneable, Serializable {
043:
044: private static final long serialVersionUID = 1421746759512286392L;
045:
046: transient int elementCount;
047:
048: transient Entry<K, V>[] elementData;
049:
050: private float loadFactor;
051:
052: private int threshold;
053:
054: transient int firstSlot;
055:
056: transient int lastSlot = -1;
057:
058: transient int modCount;
059:
060: private static final Enumeration<?> EMPTY_ENUMERATION = new Enumeration<Object>() {
061: public boolean hasMoreElements() {
062: return false;
063: }
064:
065: public Object nextElement() {
066: throw new NoSuchElementException();
067: }
068: };
069:
070: private static <K, V> Entry<K, V> newEntry(K key, V value, int hash) {
071: return new Entry<K, V>(key, value);
072: }
073:
074: private static class Entry<K, V> extends MapEntry<K, V> {
075: Entry<K, V> next;
076:
077: final int hashcode;
078:
079: Entry(K theKey, V theValue) {
080: super (theKey, theValue);
081: hashcode = theKey.hashCode();
082: }
083:
084: @Override
085: @SuppressWarnings("unchecked")
086: public Object clone() {
087: Entry<K, V> entry = (Entry<K, V>) super .clone();
088: if (next != null) {
089: entry.next = (Entry<K, V>) next.clone();
090: }
091: return entry;
092: }
093:
094: @Override
095: public V setValue(V object) {
096: if (object == null) {
097: throw new NullPointerException();
098: }
099: V result = value;
100: value = object;
101: return result;
102: }
103:
104: public int getKeyHash() {
105: return key.hashCode();
106: }
107:
108: public boolean equalsKey(Object aKey, int hash) {
109: return hashcode == aKey.hashCode() && key.equals(aKey);
110: }
111:
112: @Override
113: public String toString() {
114: return key + "=" + value; //$NON-NLS-1$
115: }
116: }
117:
118: private final class HashIterator<E> implements Iterator<E> {
119: private int position, expectedModCount;
120:
121: private final MapEntry.Type<E, K, V> type;
122:
123: private Entry<K, V> lastEntry;
124:
125: private int lastPosition;
126:
127: private boolean canRemove = false;
128:
129: HashIterator(MapEntry.Type<E, K, V> value) {
130: type = value;
131: position = lastSlot;
132: expectedModCount = modCount;
133: }
134:
135: public boolean hasNext() {
136: if (lastEntry != null && lastEntry.next != null) {
137: return true;
138: }
139: while (position >= firstSlot) {
140: if (elementData[position] == null) {
141: position--;
142: } else {
143: return true;
144: }
145: }
146: return false;
147: }
148:
149: public E next() {
150: if (expectedModCount == modCount) {
151: if (lastEntry != null) {
152: lastEntry = lastEntry.next;
153: }
154: if (lastEntry == null) {
155: while (position >= firstSlot
156: && (lastEntry = elementData[position]) == null) {
157: position--;
158: }
159: if (lastEntry != null) {
160: lastPosition = position;
161: // decrement the position so we don't find the same slot
162: // next time
163: position--;
164: }
165: }
166: if (lastEntry != null) {
167: canRemove = true;
168: return type.get(lastEntry);
169: }
170: throw new NoSuchElementException();
171: }
172: throw new ConcurrentModificationException();
173: }
174:
175: public void remove() {
176: if (expectedModCount == modCount) {
177: if (canRemove) {
178: canRemove = false;
179: synchronized (Hashtable.this ) {
180: boolean removed = false;
181: Entry<K, V> entry = elementData[lastPosition];
182: if (entry == lastEntry) {
183: elementData[lastPosition] = entry.next;
184: removed = true;
185: } else {
186: while (entry != null
187: && entry.next != lastEntry) {
188: entry = entry.next;
189: }
190: if (entry != null) {
191: entry.next = lastEntry.next;
192: removed = true;
193: }
194: }
195: if (removed) {
196: modCount++;
197: elementCount--;
198: expectedModCount++;
199: return;
200: }
201: // the entry must have been (re)moved outside of the
202: // iterator
203: // but this condition wasn't caught by the modCount
204: // check
205: // throw ConcurrentModificationException() outside of
206: // synchronized block
207: }
208: } else {
209: throw new IllegalStateException();
210: }
211: }
212: throw new ConcurrentModificationException();
213: }
214: }
215:
216: private final class HashEnumerator<E> implements Enumeration<E> {
217: boolean key;
218:
219: int start;
220:
221: Entry<K, V> entry;
222:
223: HashEnumerator(boolean isKey) {
224: key = isKey;
225: start = lastSlot + 1;
226: }
227:
228: public boolean hasMoreElements() {
229: if (entry != null) {
230: return true;
231: }
232: while (start > firstSlot) {
233: if (elementData[--start] != null) {
234: entry = elementData[start];
235: return true;
236: }
237: }
238: return false;
239: }
240:
241: @SuppressWarnings("unchecked")
242: public E nextElement() {
243: if (hasMoreElements()) {
244: Object result = key ? entry.key : entry.value;
245: entry = entry.next;
246: return (E) result;
247: }
248: throw new NoSuchElementException();
249: }
250: }
251:
252: /**
253: * Constructs a new Hashtable using the default capacity and load factor.
254: */
255: public Hashtable() {
256: this (11);
257: }
258:
259: /**
260: * Constructs a new Hashtable using the specified capacity and the default
261: * load factor.
262: *
263: * @param capacity
264: * the initial capacity
265: */
266: public Hashtable(int capacity) {
267: if (capacity >= 0) {
268: elementCount = 0;
269: elementData = newElementArray(capacity == 0 ? 1 : capacity);
270: firstSlot = elementData.length;
271: loadFactor = 0.75f;
272: computeMaxSize();
273: } else {
274: throw new IllegalArgumentException();
275: }
276: }
277:
278: /**
279: * Constructs a new Hashtable using the specified capacity and load factor.
280: *
281: * @param capacity
282: * the initial capacity
283: * @param loadFactor
284: * the initial load factor
285: */
286: public Hashtable(int capacity, float loadFactor) {
287: if (capacity >= 0 && loadFactor > 0) {
288: elementCount = 0;
289: firstSlot = capacity;
290: elementData = newElementArray(capacity == 0 ? 1 : capacity);
291: this .loadFactor = loadFactor;
292: computeMaxSize();
293: } else {
294: throw new IllegalArgumentException();
295: }
296: }
297:
298: /**
299: * Constructs a new instance of Hashtable containing the mappings from the
300: * specified Map.
301: *
302: * @param map
303: * the mappings to add
304: */
305: public Hashtable(Map<? extends K, ? extends V> map) {
306: this (map.size() < 6 ? 11 : (map.size() * 4 / 3) + 11);
307: putAll(map);
308: }
309:
310: @SuppressWarnings("unchecked")
311: private Entry<K, V>[] newElementArray(int size) {
312: return new Entry[size];
313: }
314:
315: /**
316: * Removes all key/value pairs from this Hashtable, leaving the size zero
317: * and the capacity unchanged.
318: *
319: * @see #isEmpty
320: * @see #size
321: */
322: public synchronized void clear() {
323: elementCount = 0;
324: Arrays.fill(elementData, null);
325: modCount++;
326: }
327:
328: /**
329: * Answers a new Hashtable with the same key/value pairs, capacity and load
330: * factor.
331: *
332: * @return a shallow copy of this Hashtable
333: *
334: * @see java.lang.Cloneable
335: */
336: @Override
337: @SuppressWarnings("unchecked")
338: public synchronized Object clone() {
339: try {
340: Hashtable<K, V> hashtable = (Hashtable<K, V>) super .clone();
341: hashtable.elementData = elementData.clone();
342: Entry<K, V> entry;
343: for (int i = elementData.length; --i >= 0;) {
344: if ((entry = elementData[i]) != null) {
345: hashtable.elementData[i] = (Entry<K, V>) entry
346: .clone();
347: }
348: }
349: return hashtable;
350: } catch (CloneNotSupportedException e) {
351: return null;
352: }
353: }
354:
355: private void computeMaxSize() {
356: threshold = (int) (elementData.length * loadFactor);
357: }
358:
359: /**
360: * Answers if this Hashtable contains the specified object as the value of
361: * at least one of the key/value pairs.
362: *
363: * @param value
364: * the object to look for as a value in this Hashtable
365: * @return true if object is a value in this Hashtable, false otherwise
366: *
367: * @see #containsKey
368: * @see java.lang.Object#equals
369: */
370: public synchronized boolean contains(Object value) {
371: if (value == null) {
372: throw new NullPointerException();
373: }
374:
375: for (int i = elementData.length; --i >= 0;) {
376: Entry<K, V> entry = elementData[i];
377: while (entry != null) {
378: if (entry.value.equals(value)) {
379: return true;
380: }
381: entry = entry.next;
382: }
383: }
384: return false;
385: }
386:
387: /**
388: * Answers if this Hashtable contains the specified object as a key of one
389: * of the key/value pairs.
390: *
391: * @param key
392: * the object to look for as a key in this Hashtable
393: * @return true if object is a key in this Hashtable, false otherwise
394: *
395: * @see #contains
396: * @see java.lang.Object#equals
397: */
398: public synchronized boolean containsKey(Object key) {
399: return getEntry(key) != null;
400: }
401:
402: /**
403: * Searches this Hashtable for the specified value.
404: *
405: * @param value
406: * the object to search for
407: * @return true if <code>value</code> is a value of this Hashtable, false
408: * otherwise
409: */
410: public boolean containsValue(Object value) {
411: return contains(value);
412: }
413:
414: /**
415: * Answers an Enumeration on the values of this Hashtable. The results of
416: * the Enumeration may be affected if the contents of this Hashtable are
417: * modified.
418: *
419: * @return an Enumeration of the values of this Hashtable
420: *
421: * @see #keys
422: * @see #size
423: * @see Enumeration
424: */
425: @Override
426: @SuppressWarnings("unchecked")
427: public synchronized Enumeration<V> elements() {
428: if (elementCount == 0) {
429: return (Enumeration<V>) EMPTY_ENUMERATION;
430: }
431: return new HashEnumerator<V>(false);
432: }
433:
434: /**
435: * Answers a Set of the mappings contained in this Hashtable. Each element
436: * in the set is a Map.Entry. The set is backed by this Hashtable so changes
437: * to one are reflected by the other. The set does not support adding.
438: *
439: * @return a Set of the mappings
440: */
441: public Set<Map.Entry<K, V>> entrySet() {
442: return new Collections.SynchronizedSet<Map.Entry<K, V>>(
443: new AbstractSet<Map.Entry<K, V>>() {
444: @Override
445: public int size() {
446: return elementCount;
447: }
448:
449: @Override
450: public void clear() {
451: Hashtable.this .clear();
452: }
453:
454: @Override
455: @SuppressWarnings("unchecked")
456: public boolean remove(Object object) {
457: if (contains(object)) {
458: Hashtable.this
459: .remove(((Map.Entry<K, V>) object)
460: .getKey());
461: return true;
462: }
463: return false;
464: }
465:
466: @Override
467: @SuppressWarnings("unchecked")
468: public boolean contains(Object object) {
469: Entry<K, V> entry = getEntry(((Map.Entry<K, V>) object)
470: .getKey());
471: return object.equals(entry);
472: }
473:
474: @Override
475: public Iterator<Map.Entry<K, V>> iterator() {
476: return new HashIterator<Map.Entry<K, V>>(
477: new MapEntry.Type<Map.Entry<K, V>, K, V>() {
478: public Map.Entry<K, V> get(
479: MapEntry<K, V> entry) {
480: return entry;
481: }
482: });
483: }
484: }, this );
485: }
486:
487: /**
488: * Compares the specified object to this Hashtable and answer if they are
489: * equal. The object must be an instance of Map and contain the same
490: * key/value pairs.
491: *
492: * @param object
493: * the object to compare with this object
494: * @return true if the specified object is equal to this Map, false
495: * otherwise
496: *
497: * @see #hashCode
498: */
499: @Override
500: public synchronized boolean equals(Object object) {
501: if (this == object) {
502: return true;
503: }
504: if (object instanceof Map) {
505: Map<?, ?> map = (Map<?, ?>) object;
506: if (size() != map.size()) {
507: return false;
508: }
509:
510: Set<Map.Entry<K, V>> entries = entrySet();
511: for (Map.Entry<?, ?> e : map.entrySet()) {
512: if (!entries.contains(e)) {
513: return false;
514: }
515: }
516: return true;
517: }
518: return false;
519: }
520:
521: /**
522: * Answers the value associated with the specified key in this Hashtable.
523: *
524: * @param key
525: * the key of the value returned
526: * @return the value associated with the specified key, null if the
527: * specified key does not exist
528: *
529: * @see #put
530: */
531: @Override
532: public synchronized V get(Object key) {
533: int hash = key.hashCode();
534: int index = (hash & 0x7FFFFFFF) % elementData.length;
535: Entry<K, V> entry = elementData[index];
536: while (entry != null) {
537: if (entry.equalsKey(key, hash)) {
538: return entry.value;
539: }
540: entry = entry.next;
541: }
542: return null;
543: }
544:
545: Entry<K, V> getEntry(Object key) {
546: int hash = key.hashCode();
547: int index = (hash & 0x7FFFFFFF) % elementData.length;
548: Entry<K, V> entry = elementData[index];
549: while (entry != null) {
550: if (entry.equalsKey(key, hash)) {
551: return entry;
552: }
553: entry = entry.next;
554: }
555: return null;
556: }
557:
558: /**
559: * Answers an integer hash code for the receiver. Objects which are equal
560: * answer the same value for this method.
561: *
562: * @return the receiver's hash
563: *
564: * @see #equals
565: */
566: @Override
567: public synchronized int hashCode() {
568: int result = 0;
569: Iterator<Map.Entry<K, V>> it = entrySet().iterator();
570: while (it.hasNext()) {
571: Map.Entry<K, V> entry = it.next();
572: Object key = entry.getKey();
573: Object value = entry.getValue();
574: int hash = (key != this ? key.hashCode() : 0)
575: ^ (value != this ? (value != null ? value
576: .hashCode() : 0) : 0);
577: result += hash;
578: }
579: return result;
580: }
581:
582: /**
583: * Answers if this Hashtable has no key/value pairs, a size of zero.
584: *
585: * @return true if this Hashtable has no key/value pairs, false otherwise
586: *
587: * @see #size
588: */
589: @Override
590: public synchronized boolean isEmpty() {
591: return elementCount == 0;
592: }
593:
594: /**
595: * Answers an Enumeration on the keys of this Hashtable. The results of the
596: * Enumeration may be affected if the contents of this Hashtable are
597: * modified.
598: *
599: * @return an Enumeration of the keys of this Hashtable
600: *
601: * @see #elements
602: * @see #size
603: * @see Enumeration
604: */
605: @Override
606: @SuppressWarnings("unchecked")
607: public synchronized Enumeration<K> keys() {
608: if (elementCount == 0) {
609: return (Enumeration<K>) EMPTY_ENUMERATION;
610: }
611: return new HashEnumerator<K>(true);
612: }
613:
614: /**
615: * Answers a Set of the keys contained in this Hashtable. The set is backed
616: * by this Hashtable so changes to one are reflected by the other. The set
617: * does not support adding.
618: *
619: * @return a Set of the keys
620: */
621: public Set<K> keySet() {
622: return new Collections.SynchronizedSet<K>(new AbstractSet<K>() {
623: @Override
624: public boolean contains(Object object) {
625: return containsKey(object);
626: }
627:
628: @Override
629: public int size() {
630: return elementCount;
631: }
632:
633: @Override
634: public void clear() {
635: Hashtable.this .clear();
636: }
637:
638: @Override
639: public boolean remove(Object key) {
640: if (containsKey(key)) {
641: Hashtable.this .remove(key);
642: return true;
643: }
644: return false;
645: }
646:
647: @Override
648: public Iterator<K> iterator() {
649: return new HashIterator<K>(
650: new MapEntry.Type<K, K, V>() {
651: public K get(MapEntry<K, V> entry) {
652: return entry.key;
653: }
654: });
655: }
656: }, this );
657: }
658:
659: /**
660: * Associate the specified value with the specified key in this Hashtable.
661: * If the key already exists, the old value is replaced. The key and value
662: * cannot be null.
663: *
664: * @param key
665: * the key to add
666: * @param value
667: * the value to add
668: * @return the old value associated with the specified key, null if the key
669: * did not exist
670: *
671: * @see #elements
672: * @see #get
673: * @see #keys
674: * @see java.lang.Object#equals
675: */
676: @Override
677: public synchronized V put(K key, V value) {
678: if (key != null && value != null) {
679: int hash = key.hashCode();
680: int index = (hash & 0x7FFFFFFF) % elementData.length;
681: Entry<K, V> entry = elementData[index];
682: while (entry != null && !entry.equalsKey(key, hash)) {
683: entry = entry.next;
684: }
685: if (entry == null) {
686: modCount++;
687: if (++elementCount > threshold) {
688: rehash();
689: index = (hash & 0x7FFFFFFF) % elementData.length;
690: }
691: if (index < firstSlot) {
692: firstSlot = index;
693: }
694: if (index > lastSlot) {
695: lastSlot = index;
696: }
697: entry = newEntry(key, value, hash);
698: entry.next = elementData[index];
699: elementData[index] = entry;
700: return null;
701: }
702: V result = entry.value;
703: entry.value = value;
704: return result;
705: }
706: throw new NullPointerException();
707: }
708:
709: /**
710: * Copies every mapping in the specified Map to this Hashtable.
711: *
712: * @param map
713: * the Map to copy mappings from
714: */
715: public synchronized void putAll(Map<? extends K, ? extends V> map) {
716: for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
717: put(entry.getKey(), entry.getValue());
718: }
719: }
720:
721: /**
722: * Increases the capacity of this Hashtable. This method is sent when the
723: * size of this Hashtable exceeds the load factor.
724: */
725: protected void rehash() {
726: int length = (elementData.length << 1) + 1;
727: if (length == 0) {
728: length = 1;
729: }
730: int newFirst = length;
731: int newLast = -1;
732: Entry<K, V>[] newData = newElementArray(length);
733: for (int i = lastSlot + 1; --i >= firstSlot;) {
734: Entry<K, V> entry = elementData[i];
735: while (entry != null) {
736: int index = (entry.getKeyHash() & 0x7FFFFFFF) % length;
737: if (index < newFirst) {
738: newFirst = index;
739: }
740: if (index > newLast) {
741: newLast = index;
742: }
743: Entry<K, V> next = entry.next;
744: entry.next = newData[index];
745: newData[index] = entry;
746: entry = next;
747: }
748: }
749: firstSlot = newFirst;
750: lastSlot = newLast;
751: elementData = newData;
752: computeMaxSize();
753: }
754:
755: /**
756: * Remove the key/value pair with the specified key from this Hashtable.
757: *
758: * @param key
759: * the key to remove
760: * @return the value associated with the specified key, null if the
761: * specified key did not exist
762: *
763: * @see #get
764: * @see #put
765: */
766: @Override
767: public synchronized V remove(Object key) {
768: int hash = key.hashCode();
769: int index = (hash & 0x7FFFFFFF) % elementData.length;
770: Entry<K, V> last = null;
771: Entry<K, V> entry = elementData[index];
772: while (entry != null && !entry.equalsKey(key, hash)) {
773: last = entry;
774: entry = entry.next;
775: }
776: if (entry != null) {
777: modCount++;
778: if (last == null) {
779: elementData[index] = entry.next;
780: } else {
781: last.next = entry.next;
782: }
783: elementCount--;
784: V result = entry.value;
785: entry.value = null;
786: return result;
787: }
788: return null;
789: }
790:
791: /**
792: * Answers the number of key/value pairs in this Hashtable.
793: *
794: * @return the number of key/value pairs in this Hashtable
795: *
796: * @see #elements
797: * @see #keys
798: */
799: @Override
800: public synchronized int size() {
801: return elementCount;
802: }
803:
804: /**
805: * Answers the string representation of this Hashtable.
806: *
807: * @return the string representation of this Hashtable
808: */
809: @Override
810: public synchronized String toString() {
811: if (isEmpty()) {
812: return "{}"; //$NON-NLS-1$
813: }
814:
815: StringBuilder buffer = new StringBuilder(size() * 28);
816: buffer.append('{');
817: for (int i = lastSlot; i >= firstSlot; i--) {
818: Entry<K, V> entry = elementData[i];
819: while (entry != null) {
820: if (entry.key != this ) {
821: buffer.append(entry.key);
822: } else {
823: // luni.04=this Map
824: buffer
825: .append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
826: }
827: buffer.append('=');
828: if (entry.value != this ) {
829: buffer.append(entry.value);
830: } else {
831: // luni.04=this Map
832: buffer
833: .append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
834: }
835: buffer.append(", "); //$NON-NLS-1$
836: entry = entry.next;
837: }
838: }
839: // Remove the last ", "
840: if (elementCount > 0) {
841: buffer.setLength(buffer.length() - 2);
842: }
843: buffer.append('}');
844: return buffer.toString();
845: }
846:
847: /**
848: * Answers a Collection of the values contained in this Hashtable. The
849: * collection is backed by this Hashtable so changes to one are reflected by
850: * the other. The collection does not support adding.
851: *
852: * @return a Collection of the values
853: */
854: public Collection<V> values() {
855: return new Collections.SynchronizedCollection<V>(
856: new AbstractCollection<V>() {
857: @Override
858: public boolean contains(Object object) {
859: return Hashtable.this .contains(object);
860: }
861:
862: @Override
863: public int size() {
864: return elementCount;
865: }
866:
867: @Override
868: public void clear() {
869: Hashtable.this .clear();
870: }
871:
872: @Override
873: public Iterator<V> iterator() {
874: return new HashIterator<V>(
875: new MapEntry.Type<V, K, V>() {
876: public V get(MapEntry<K, V> entry) {
877: return entry.value;
878: }
879: });
880: }
881: }, this );
882: }
883:
884: private synchronized void writeObject(ObjectOutputStream stream)
885: throws IOException {
886: stream.defaultWriteObject();
887: stream.writeInt(elementData.length);
888: stream.writeInt(elementCount);
889: for (int i = elementData.length; --i >= 0;) {
890: Entry<K, V> entry = elementData[i];
891: while (entry != null) {
892: stream.writeObject(entry.key);
893: stream.writeObject(entry.value);
894: entry = entry.next;
895: }
896: }
897: }
898:
899: @SuppressWarnings("unchecked")
900: private void readObject(ObjectInputStream stream)
901: throws IOException, ClassNotFoundException {
902: stream.defaultReadObject();
903: int length = stream.readInt();
904: elementData = newElementArray(length);
905: elementCount = stream.readInt();
906: for (int i = elementCount; --i >= 0;) {
907: Object key = stream.readObject();
908: int hash = key.hashCode();
909: int index = (hash & 0x7FFFFFFF) % length;
910: if (index < firstSlot) {
911: firstSlot = index;
912: }
913: if (index > lastSlot) {
914: lastSlot = index;
915: }
916: Entry<K, V> entry = newEntry((K) key, (V) stream
917: .readObject(), hash);
918: entry.next = elementData[index];
919: elementData[index] = entry;
920: }
921: }
922: }
|