Java集合源码分析(二十一)-Hashtable(一)类

108 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

源码

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
}

注释内容

  • 这个类实现 hash table,映射 key 到 value。任何 non-null 对象能够被用作 key 或 value
  • 要从 hash table 成功存储和检索,用作 key 的对象必须实现 hashCode 和 equals 方法
  • Hashtable 实例有两个影响性能的参数:initial capacity 和 load factor。capacity 是 hash table 中 buckets 的数量,initial capacity 只是 hash table 创建时的容量。请注意,hash table 是 open:在“哈希冲突”的情况下,单个 bucket 存储多个 entry,必须按顺序搜索。load factor 是在自动增加它的容量之前,允许 hash table 多满的估量。initial capacity 和 load factor 参数仅仅是对实现的提示。何时和如何调用 rehash 方法明确细节取决于实现
  • 通常,默认load factor(0.75)在时间和空间成本提供好的平衡。更高的值减少空间开销,但增加查找 entry 的时间花费(影响大多数 Hashtable 操作,包括 get 和 put)
  • initial capacity 控制浪费空间和需要 rehash 操作的平衡,这很耗时。如果 initial capacity 大于 Hashtable 中 entries 的最大值除以它的 load factor,不会再发生 rehash 操作。然而,设置 initial capacity 太高会浪费空间
  • 如果要在 Hsahtable 创建很多 entry,使用一个非常大容量的创建它,可以允许更高效地插入 entry,而不是让它根据需要自动执行重新哈希去增大表
  • 这个例子创建一个数字的 hashtable。它使用数字的名称作为 key
ashtable<String, Integer> numbers = new Hashtable<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
  • 检索数字,使用下面的代码
Integer n = numbers.get("two");
if (n != null) {
    System.out.println("two = " + n);
}
  • 这个类所有的“集合视图方法”返回的集合的 iterator 方法返回的迭代器是 fail-fast。如果在 iterator 被创建后,除了通过迭代器自己的 remove 方法,用任何方式修改 Hashtable 结构,迭代器将抛出 ConcurrentModificationException。因此,面对并发修改,iterator 快速和干净地失败,而不是在未来不确定的时间冒着任意的,不确定的操作的风险。Hashtable 的 keys 和 elements 方法返回的 Enumerations 不是 fail-fast
  • 注意:iterator 的 fail-fast 行为不能确保,一般来说,不可能在非同步的并发修改的情况做任何硬保证。Fail-fast 迭代器最大努力抛出 ConcurrentModificationException。因此,写一个依赖这个异常的正确性的程序是错误的:iterators 的 fail-fast 行为应该只被用于检测 bug
  • 从 Java 2 平台 v1.2 这个类改造为实现 Map 接口,让它作为 Java Collections Framework 的一员。不像新的集合实现,Hashtable 是同步的。如果不需要线程安全实现,推荐使用 HashMap 代替 Hashtable。如果渴望线程安全高度并发的实现,那么建议使用 ConcurrentHashMap 代替 Hashtable

KeySet

public class Hashtable<K, V>
        extends Dictionary<K, V>
        implements Map<K, V>, Cloneable, java.io.Serializable {
    private class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return getIterator(KEYS);
        }

        public int size() {
            return count;
        }

        public boolean contains(Object o) {
            return containsKey(o);
        }

        public boolean remove(Object o) {
            return Hashtable.this.remove(o) != null;
        }

        public void clear() {
            Hashtable.this.clear();
        }
    }
}

EntrySet

public class Hashtable<K,V>
        extends Dictionary<K,V>
        implements Map<K,V>, Cloneable, java.io.Serializable {
    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return getIterator(ENTRIES);
        }

        public boolean add(Map.Entry<K,V> o) {
            return super.add(o);
        }

        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
            Object key = entry.getKey();
            Entry<?,?>[] tab = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;

            for (Entry<?,?> e = tab[index]; e != null; e = e.next)
                if (e.hash==hash && e.equals(entry))
                    return true;
            return false;
        }

        public boolean remove(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
            Object key = entry.getKey();
            Entry<?,?>[] tab = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;

            @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>)tab[index];
            for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
                if (e.hash==hash && e.equals(entry)) {
                    modCount++;
                    if (prev != null)
                        prev.next = e.next;
                    else
                        tab[index] = e.next;

                    count--;
                    e.value = null;
                    return true;
                }
            }
            return false;
        }

        public int size() {
            return count;
        }

        public void clear() {
            Hashtable.this.clear();
        }
    }
}

ValueCollection

public class Hashtable<K, V>
        extends Dictionary<K, V>
        implements Map<K, V>, Cloneable, java.io.Serializable {
    private class ValueCollection extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return getIterator(VALUES);
        }

        public int size() {
            return count;
        }

        public boolean contains(Object o) {
            return containsValue(o);
        }

        public void clear() {
            Hashtable.this.clear();
        }
    }
}

Entry

public class Hashtable<K, V>
        extends Dictionary<K, V>
        implements Map<K, V>, Cloneable, java.io.Serializable {
    /**
     * Hashtable bucket collision list entry
     */
    private static class Entry<K, V> implements Map.Entry<K, V> {
        final int hash;
        final K key;
        V value;
        Entry<K, V> next;

        protected Entry(int hash, K key, V value, Entry<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        @SuppressWarnings("unchecked")
        protected Object clone() {
            return new Entry<>(hash, key, value,
                    (next == null ? null : (Entry<K, V>) next.clone()));
        }

        // Map.Entry Ops

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public V setValue(V value) {
            if (value == null)
                throw new NullPointerException();

            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;

            return (key == null ? e.getKey() == null : key.equals(e.getKey())) &&
                    (value == null ? e.getValue() == null : value.equals(e.getValue()));
        }

        public int hashCode() {
            return hash ^ Objects.hashCode(value);
        }

        public String toString() {
            return key.toString() + "=" + value.toString();
        }
    }
}

Enumerator

public class Hashtable<K, V>
        extends Dictionary<K, V>
        implements Map<K, V>, Cloneable, java.io.Serializable {
    /**
     * A hashtable enumerator class.  This class implements both the
     * Enumeration and Iterator interfaces, but individual instances
     * can be created with the Iterator methods disabled.  This is necessary
     * to avoid unintentionally increasing the capabilities granted a user
     * by passing an Enumeration.
     */
    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
        Entry<?, ?>[] table = Hashtable.this.table;
        int index = table.length;
        Entry<?, ?> entry;
        Entry<?, ?> lastReturned;
        int type;

        /**
         * Indicates whether this Enumerator is serving as an Iterator
         * or an Enumeration.  (true -> Iterator).
         */
        boolean iterator;

        /**
         * The modCount value that the iterator believes that the backing
         * Hashtable should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        protected int expectedModCount = modCount;

        Enumerator(int type, boolean iterator) {
            this.type = type;
            this.iterator = iterator;
        }

        public boolean hasMoreElements() {
            Entry<?, ?> e = entry;
            int i = index;
            Entry<?, ?>[] t = table;
            /* Use locals for faster loop iteration */
            while (e == null && i > 0) {
                e = t[--i];
            }
            entry = e;
            index = i;
            return e != null;
        }

        @SuppressWarnings("unchecked")
        public T nextElement() {
            Entry<?, ?> et = entry;
            int i = index;
            Entry<?, ?>[] t = table;
            /* Use locals for faster loop iteration */
            while (et == null && i > 0) {
                et = t[--i];
            }
            entry = et;
            index = i;
            if (et != null) {
                Entry<?, ?> e = lastReturned = entry;
                entry = e.next;
                return type == KEYS ? (T) e.key : (type == VALUES ? (T) e.value : (T) e);
            }
            throw new NoSuchElementException("Hashtable Enumerator");
        }

        // Iterator methods
        public boolean hasNext() {
            return hasMoreElements();
        }

        public T next() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return nextElement();
        }

        public void remove() {
            if (!iterator)
                throw new UnsupportedOperationException();
            if (lastReturned == null)
                throw new IllegalStateException("Hashtable Enumerator");
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            synchronized (Hashtable.this) {
                Entry<?, ?>[] tab = Hashtable.this.table;
                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;

                @SuppressWarnings("unchecked")
                Entry<K, V> e = (Entry<K, V>) tab[index];
                for (Entry<K, V> prev = null; e != null; prev = e, e = e.next) {
                    if (e == lastReturned) {
                        modCount++;
                        expectedModCount++;
                        if (prev == null)
                            tab[index] = e.next;
                        else
                            prev.next = e.next;
                        count--;
                        lastReturned = null;
                        return;
                    }
                }
                throw new ConcurrentModificationException();
            }
        }
    }
}

注释内容

  • hashtable 枚举类。这个类实现了 Enumeration 和 Iterator 接口,但可以在禁用 Iterator 方法时创建单个实例。避免通过传递 Enumeration 无意中增加授予用户的能力是必要的

字段

  • boolean iterator:表明这个 Enumerator 作为 Iterator 或者 Enumeration(true -> Iterator)
  • protected int expectedModCount = modCount:iterator 相信支持 Hashtable 应该有 modCount 值。如果违反这个预期,iterator 发现并发修改