diff options
Diffstat (limited to 'libjava/classpath/java/util/Hashtable.java')
-rw-r--r-- | libjava/classpath/java/util/Hashtable.java | 349 |
1 files changed, 249 insertions, 100 deletions
diff --git a/libjava/classpath/java/util/Hashtable.java b/libjava/classpath/java/util/Hashtable.java index 4c00d18a8e2..2e265a47387 100644 --- a/libjava/classpath/java/util/Hashtable.java +++ b/libjava/classpath/java/util/Hashtable.java @@ -100,8 +100,8 @@ import java.io.Serializable; * @since 1.0 * @status updated to 1.4 */ -public class Hashtable extends Dictionary - implements Map, Cloneable, Serializable +public class Hashtable<K, V> extends Dictionary<K, V> + implements Map<K, V>, Cloneable, Serializable { // WARNING: Hashtable is a CORE class in the bootstrap cycle. See the // comments in vm/reference/java/lang/Runtime for implications of this fact. @@ -139,7 +139,7 @@ public class Hashtable extends Dictionary * Array containing the actual key-value mappings. */ // Package visible for use by nested classes. - transient HashEntry[] buckets; + transient HashEntry<K, V>[] buckets; /** * Counts the number of modifications this Hashtable has undergone, used @@ -157,34 +157,35 @@ public class Hashtable extends Dictionary /** * The cache for {@link #keySet()}. */ - private transient Set keys; + private transient Set<K> keys; /** * The cache for {@link #values()}. */ - private transient Collection values; + private transient Collection<V> values; /** * The cache for {@link #entrySet()}. */ - private transient Set entries; + private transient Set<Map.Entry<K, V>> entries; /** * Class to represent an entry in the hash table. Holds a single key-value * pair. A Hashtable Entry is identical to a HashMap Entry, except that * `null' is not allowed for keys and values. */ - private static final class HashEntry extends AbstractMap.BasicMapEntry + private static final class HashEntry<K, V> + extends AbstractMap.SimpleEntry<K, V> { /** The next entry in the linked list. */ - HashEntry next; + HashEntry<K, V> next; /** * Simple constructor. * @param key the key, already guaranteed non-null * @param value the value, already guaranteed non-null */ - HashEntry(Object key, Object value) + HashEntry(K key, V value) { super(key, value); } @@ -195,7 +196,7 @@ public class Hashtable extends Dictionary * @return the prior value * @throws NullPointerException if <code>newVal</code> is null */ - public Object setValue(Object newVal) + public V setValue(V newVal) { if (newVal == null) throw new NullPointerException(); @@ -226,7 +227,7 @@ public class Hashtable extends Dictionary * to or from `null'. * @since 1.2 */ - public Hashtable(Map m) + public Hashtable(Map<? extends K, ? extends V> m) { this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); putAll(m); @@ -263,7 +264,7 @@ public class Hashtable extends Dictionary if (initialCapacity == 0) initialCapacity = 1; - buckets = new HashEntry[initialCapacity]; + buckets = (HashEntry<K, V>[]) new HashEntry[initialCapacity]; this.loadFactor = loadFactor; threshold = (int) (initialCapacity * loadFactor); } @@ -295,7 +296,7 @@ public class Hashtable extends Dictionary * @see #elements() * @see #keySet() */ - public Enumeration keys() + public Enumeration<K> keys() { return new KeyEnumerator(); } @@ -309,7 +310,7 @@ public class Hashtable extends Dictionary * @see #keys() * @see #values() */ - public Enumeration elements() + public Enumeration<V> elements() { return new ValueEnumerator(); } @@ -333,7 +334,7 @@ public class Hashtable extends Dictionary for (int i = buckets.length - 1; i >= 0; i--) { - HashEntry e = buckets[i]; + HashEntry<K, V> e = buckets[i]; while (e != null) { if (e.value.equals(value)) @@ -341,7 +342,7 @@ public class Hashtable extends Dictionary e = e.next; } } - + return false; } @@ -376,7 +377,7 @@ public class Hashtable extends Dictionary public synchronized boolean containsKey(Object key) { int idx = hash(key); - HashEntry e = buckets[idx]; + HashEntry<K, V> e = buckets[idx]; while (e != null) { if (e.key.equals(key)) @@ -396,10 +397,10 @@ public class Hashtable extends Dictionary * @see #put(Object, Object) * @see #containsKey(Object) */ - public synchronized Object get(Object key) + public synchronized V get(Object key) { int idx = hash(key); - HashEntry e = buckets[idx]; + HashEntry<K, V> e = buckets[idx]; while (e != null) { if (e.key.equals(key)) @@ -421,10 +422,10 @@ public class Hashtable extends Dictionary * @see #get(Object) * @see Object#equals(Object) */ - public synchronized Object put(Object key, Object value) + public synchronized V put(K key, V value) { int idx = hash(key); - HashEntry e = buckets[idx]; + HashEntry<K, V> e = buckets[idx]; // Check if value is null since it is not permitted. if (value == null) @@ -435,7 +436,7 @@ public class Hashtable extends Dictionary if (e.key.equals(key)) { // Bypass e.setValue, since we already know value is non-null. - Object r = e.value; + V r = e.value; e.value = value; return r; } @@ -454,7 +455,7 @@ public class Hashtable extends Dictionary idx = hash(key); } - e = new HashEntry(key, value); + e = new HashEntry<K, V>(key, value); e.next = buckets[idx]; buckets[idx] = e; @@ -470,11 +471,11 @@ public class Hashtable extends Dictionary * @param key the key used to locate the value to remove * @return whatever the key mapped to, if present */ - public synchronized Object remove(Object key) + public synchronized V remove(Object key) { int idx = hash(key); - HashEntry e = buckets[idx]; - HashEntry last = null; + HashEntry<K, V> e = buckets[idx]; + HashEntry<K, V> last = null; while (e != null) { @@ -502,17 +503,19 @@ public class Hashtable extends Dictionary * @param m the map to be hashed into this * @throws NullPointerException if m is null, or contains null keys or values */ - public synchronized void putAll(Map m) + public synchronized void putAll(Map<? extends K, ? extends V> m) { - Iterator itr = m.entrySet().iterator(); + Map<K,V> addMap; + + addMap = (Map<K,V>) m; - while (itr.hasNext()) + for (Map.Entry<K,V> e : addMap.entrySet()) { - Map.Entry e = (Map.Entry) itr.next(); // Optimize in case the Entry is one of our own. - if (e instanceof AbstractMap.BasicMapEntry) + if (e instanceof AbstractMap.SimpleEntry) { - AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e; + AbstractMap.SimpleEntry<? extends K, ? extends V> entry + = (AbstractMap.SimpleEntry<? extends K, ? extends V>) e; put(entry.key, entry.value); } else @@ -543,16 +546,16 @@ public class Hashtable extends Dictionary */ public synchronized Object clone() { - Hashtable copy = null; + Hashtable<K, V> copy = null; try { - copy = (Hashtable) super.clone(); + copy = (Hashtable<K, V>) super.clone(); } catch (CloneNotSupportedException x) { // This is impossible. } - copy.buckets = new HashEntry[buckets.length]; + copy.buckets = (HashEntry<K, V>[]) new HashEntry[buckets.length]; copy.putAllInternal(this); // Clear the caches. copy.keys = null; @@ -576,7 +579,7 @@ public class Hashtable extends Dictionary // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the // unsynchronized EntryIterator instead. - Iterator entries = new EntryIterator(); + Iterator<Map.Entry<K, V>> entries = new EntryIterator(); StringBuffer r = new StringBuffer("{"); for (int pos = size; pos > 0; pos--) { @@ -603,20 +606,20 @@ public class Hashtable extends Dictionary * @see #entrySet() * @since 1.2 */ - public Set keySet() + public Set<K> keySet() { if (keys == null) { // Create a synchronized AbstractSet with custom implementations of // those methods that can be overridden easily and efficiently. - Set r = new AbstractSet() + Set<K> r = new AbstractSet<K>() { public int size() { return size; } - public Iterator iterator() + public Iterator<K> iterator() { return new KeyIterator(); } @@ -640,7 +643,7 @@ public class Hashtable extends Dictionary }; // We must specify the correct object to synchronize upon, hence the // use of a non-public API - keys = new Collections.SynchronizedSet(this, r); + keys = new Collections.SynchronizedSet<K>(this, r); } return keys; } @@ -661,20 +664,20 @@ public class Hashtable extends Dictionary * @see #entrySet() * @since 1.2 */ - public Collection values() + public Collection<V> values() { if (values == null) { // We don't bother overriding many of the optional methods, as doing so // wouldn't provide any significant performance advantage. - Collection r = new AbstractCollection() + Collection<V> r = new AbstractCollection<V>() { public int size() { return size; } - public Iterator iterator() + public Iterator<V> iterator() { return new ValueIterator(); } @@ -686,7 +689,7 @@ public class Hashtable extends Dictionary }; // We must specify the correct object to synchronize upon, hence the // use of a non-public API - values = new Collections.SynchronizedCollection(this, r); + values = new Collections.SynchronizedCollection<V>(this, r); } return values; } @@ -713,20 +716,20 @@ public class Hashtable extends Dictionary * @see Map.Entry * @since 1.2 */ - public Set entrySet() + public Set<Map.Entry<K, V>> entrySet() { if (entries == null) { // Create an AbstractSet with custom implementations of those methods // that can be overridden easily and efficiently. - Set r = new AbstractSet() + Set<Map.Entry<K, V>> r = new AbstractSet<Map.Entry<K, V>>() { public int size() { return size; } - public Iterator iterator() + public Iterator<Map.Entry<K, V>> iterator() { return new EntryIterator(); } @@ -743,7 +746,7 @@ public class Hashtable extends Dictionary public boolean remove(Object o) { - HashEntry e = getEntry(o); + HashEntry<K, V> e = getEntry(o); if (e != null) { Hashtable.this.remove(e.key); @@ -754,7 +757,7 @@ public class Hashtable extends Dictionary }; // We must specify the correct object to synchronize upon, hence the // use of a non-public API - entries = new Collections.SynchronizedSet(this, r); + entries = new Collections.SynchronizedSet<Map.Entry<K, V>>(this, r); } return entries; } @@ -772,7 +775,7 @@ public class Hashtable extends Dictionary */ public boolean equals(Object o) { - // no need to synchronize, entrySet().equals() does that + // no need to synchronize, entrySet().equals() does that. if (o == this) return true; if (!(o instanceof Map)) @@ -793,7 +796,7 @@ public class Hashtable extends Dictionary // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the // unsynchronized EntryIterator instead. - Iterator itr = new EntryIterator(); + Iterator<Map.Entry<K, V>> itr = new EntryIterator(); int hashcode = 0; for (int pos = size; pos > 0; pos--) hashcode += itr.next().hashCode(); @@ -826,16 +829,16 @@ public class Hashtable extends Dictionary * @see #entrySet() */ // Package visible, for use in nested classes. - HashEntry getEntry(Object o) + HashEntry<K, V> getEntry(Object o) { if (! (o instanceof Map.Entry)) return null; - Object key = ((Map.Entry) o).getKey(); + K key = ((Map.Entry<K, V>) o).getKey(); if (key == null) return null; int idx = hash(key); - HashEntry e = buckets[idx]; + HashEntry<K, V> e = buckets[idx]; while (e != null) { if (e.equals(o)) @@ -852,18 +855,19 @@ public class Hashtable extends Dictionary * * @param m the map to initialize this from */ - void putAllInternal(Map m) + void putAllInternal(Map<? extends K, ? extends V> m) { - Iterator itr = m.entrySet().iterator(); + Map<K,V> addMap; + + addMap = (Map<K,V>) m; size = 0; - while (itr.hasNext()) + for (Map.Entry<K,V> e : addMap.entrySet()) { size++; - Map.Entry e = (Map.Entry) itr.next(); - Object key = e.getKey(); + K key = e.getKey(); int idx = hash(key); - HashEntry he = new HashEntry(key, e.getValue()); + HashEntry<K, V> he = new HashEntry<K, V>(key, e.getValue()); he.next = buckets[idx]; buckets[idx] = he; } @@ -882,19 +886,19 @@ public class Hashtable extends Dictionary */ protected void rehash() { - HashEntry[] oldBuckets = buckets; + HashEntry<K, V>[] oldBuckets = buckets; int newcapacity = (buckets.length * 2) + 1; threshold = (int) (newcapacity * loadFactor); - buckets = new HashEntry[newcapacity]; + buckets = (HashEntry<K, V>[]) new HashEntry[newcapacity]; for (int i = oldBuckets.length - 1; i >= 0; i--) { - HashEntry e = oldBuckets[i]; + HashEntry<K, V> e = oldBuckets[i]; while (e != null) { int idx = hash(e.key); - HashEntry dest = buckets[idx]; + HashEntry<K, V> dest = buckets[idx]; if (dest != null) { @@ -911,7 +915,7 @@ public class Hashtable extends Dictionary buckets[idx] = e; } - HashEntry next = e.next; + HashEntry<K, V> next = e.next; e.next = null; e = next; } @@ -939,10 +943,10 @@ public class Hashtable extends Dictionary // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the // unsynchronized EntryIterator instead. - Iterator it = new EntryIterator(); + Iterator<Map.Entry<K, V>> it = new EntryIterator(); while (it.hasNext()) { - HashEntry entry = (HashEntry) it.next(); + HashEntry<K, V> entry = (HashEntry<K, V>) it.next(); s.writeObject(entry.key); s.writeObject(entry.value); } @@ -966,13 +970,13 @@ public class Hashtable extends Dictionary s.defaultReadObject(); // Read and use capacity. - buckets = new HashEntry[s.readInt()]; + buckets = (HashEntry<K, V>[]) new HashEntry[s.readInt()]; int len = s.readInt(); // Read and use key/value pairs. // TODO: should we be defensive programmers, and check for illegal nulls? while (--len >= 0) - put(s.readObject(), s.readObject()); + put((K) s.readObject(), (V) s.readObject()); } /** @@ -987,7 +991,8 @@ public class Hashtable extends Dictionary * @author Jon Zeppieri * @author Fridjof Siebert */ - private class EntryIterator implements Iterator + private class EntryIterator + implements Iterator<Entry<K,V>> { /** * The number of modifications to the backing Hashtable that we know about. @@ -998,16 +1003,16 @@ public class Hashtable extends Dictionary /** Current index in the physical hash table. */ int idx = buckets.length; /** The last Entry returned by a next() call. */ - HashEntry last; + HashEntry<K, V> last; /** * The next entry that should be returned by next(). It is set to something * if we're iterating through a bucket that contains multiple linked * entries. It is null if next() needs to find a new bucket. */ - HashEntry next; + HashEntry<K, V> next; /** - * Construct a new EtryIterator + * Construct a new EntryIterator */ EntryIterator() { @@ -1029,14 +1034,14 @@ public class Hashtable extends Dictionary * @throws ConcurrentModificationException if the hashtable was modified * @throws NoSuchElementException if there is none */ - public Object next() + public Map.Entry<K,V> next() { if (knownMod != modCount) throw new ConcurrentModificationException(); if (count == 0) throw new NoSuchElementException(); count--; - HashEntry e = next; + HashEntry<K, V> e = next; while (e == null) if (idx <= 0) @@ -1070,12 +1075,43 @@ public class Hashtable extends Dictionary /** * A class which implements the Iterator interface and is used for - * iterating over keys in Hashtables. + * iterating over keys in Hashtables. This class uses an + * <code>EntryIterator</code> to obtain the keys of each entry. * * @author Fridtjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - private class KeyIterator extends EntryIterator + private class KeyIterator + implements Iterator<K> { + + /** + * This entry iterator is used for most operations. Only + * <code>next()</code> gives a different result, by returning just + * the key rather than the whole element. + */ + private EntryIterator iterator; + + /** + * Construct a new KeyIterator + */ + KeyIterator() + { + iterator = new EntryIterator(); + } + + + /** + * Returns true if the entry iterator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasNext() + { + return iterator.hasNext(); + } + /** * Returns the next element in the Iterator's sequential view. * @@ -1084,34 +1120,88 @@ public class Hashtable extends Dictionary * @throws ConcurrentModificationException if the hashtable was modified * @throws NoSuchElementException if there is none */ - public Object next() + public K next() { - return ((HashEntry)super.next()).key; + return ((HashEntry<K,V>) iterator.next()).key; } - } // class KeyIterator - - + /** + * Removes the last element used by the <code>next()</code> method + * using the entry iterator. + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + iterator.remove(); + } + } // class KeyIterator + /** * A class which implements the Iterator interface and is used for - * iterating over values in Hashtables. + * iterating over values in Hashtables. This class uses an + * <code>EntryIterator</code> to obtain the values of each entry. * * @author Fridtjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - private class ValueIterator extends EntryIterator + private class ValueIterator + implements Iterator<V> { + /** - * Returns the next element in the Iterator's sequential view. + * This entry iterator is used for most operations. Only + * <code>next()</code> gives a different result, by returning just + * the value rather than the whole element. + */ + private EntryIterator iterator; + + /** + * Construct a new KeyIterator + */ + ValueIterator() + { + iterator = new EntryIterator(); + } + + + /** + * Returns true if the entry iterator has more elements. * - * @return the next element + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasNext() + { + return iterator.hasNext(); + } + + /** + * Returns the value of the next element in the iterator's sequential view. + * + * @return the next value * * @throws ConcurrentModificationException if the hashtable was modified * @throws NoSuchElementException if there is none */ - public Object next() + public V next() + { + return ((HashEntry<K,V>) iterator.next()).value; + } + + /** + * Removes the last element used by the <code>next()</code> method + * using the entry iterator. + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() { - return ((HashEntry)super.next()).value; + iterator.remove(); } + } // class ValueIterator /** @@ -1128,7 +1218,8 @@ public class Hashtable extends Dictionary * @author Jon Zeppieri * @author Fridjof Siebert */ - private class EntryEnumerator implements Enumeration + private class EntryEnumerator + implements Enumeration<Entry<K,V>> { /** The number of elements remaining to be returned by next(). */ int count = size; @@ -1139,7 +1230,7 @@ public class Hashtable extends Dictionary * set if we are iterating through a bucket with multiple entries, or null * if we must look in the next bucket. */ - HashEntry next; + HashEntry<K, V> next; /** * Construct the enumeration. @@ -1163,12 +1254,12 @@ public class Hashtable extends Dictionary * @return the next element * @throws NoSuchElementException if there is none. */ - public Object nextElement() + public Map.Entry<K,V> nextElement() { if (count == 0) throw new NoSuchElementException("Hashtable Enumerator"); count--; - HashEntry e = next; + HashEntry<K, V> e = next; while (e == null) if (idx <= 0) @@ -1195,18 +1286,47 @@ public class Hashtable extends Dictionary * * @author Jon Zeppieri * @author Fridjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - private final class KeyEnumerator extends EntryEnumerator + private final class KeyEnumerator + implements Enumeration<K> { /** + * This entry enumerator is used for most operations. Only + * <code>nextElement()</code> gives a different result, by returning just + * the key rather than the whole element. + */ + private EntryEnumerator enumerator; + + /** + * Construct a new KeyEnumerator + */ + KeyEnumerator() + { + enumerator = new EntryEnumerator(); + } + + + /** + * Returns true if the entry enumerator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasMoreElements() + { + return enumerator.hasMoreElements(); + } + + /** * Returns the next element. * @return the next element * @throws NoSuchElementException if there is none. */ - public Object nextElement() + public K nextElement() { - HashEntry entry = (HashEntry) super.nextElement(); - Object retVal = null; + HashEntry<K,V> entry = (HashEntry<K,V>) enumerator.nextElement(); + K retVal = null; if (entry != null) retVal = entry.key; return retVal; @@ -1227,18 +1347,47 @@ public class Hashtable extends Dictionary * * @author Jon Zeppieri * @author Fridjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - private final class ValueEnumerator extends EntryEnumerator + private final class ValueEnumerator + implements Enumeration<V> { /** + * This entry enumerator is used for most operations. Only + * <code>nextElement()</code> gives a different result, by returning just + * the value rather than the whole element. + */ + private EntryEnumerator enumerator; + + /** + * Construct a new ValueEnumerator + */ + ValueEnumerator() + { + enumerator = new EntryEnumerator(); + } + + + /** + * Returns true if the entry enumerator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasMoreElements() + { + return enumerator.hasMoreElements(); + } + + /** * Returns the next element. * @return the next element * @throws NoSuchElementException if there is none. */ - public Object nextElement() + public V nextElement() { - HashEntry entry = (HashEntry) super.nextElement(); - Object retVal = null; + HashEntry<K,V> entry = (HashEntry<K,V>) enumerator.nextElement(); + V retVal = null; if (entry != null) retVal = entry.value; return retVal; |