Java集合源码分析09----Hashtable源码分析

目录

简介

介绍

源码分析(jdk1.8)

迭代Hashtable

Hashtable与HashMap的区别


------分析基于jdk1.8.

简介

Hashtable是jdk1.0引入,与HashMap一样,是用散列表(哈希表)实现的,存储的是键-值对映射。Hashtable继承了抽象类Dictionary,实现了Map、Cloneable、java.io.Serializable接口,所以可以克隆,进行序列化传输。

需要注意的是Hashtable是不允许存储null值和null键(会抛出NullPointerException异常),Hashtable中大部分的方法都使用了synchronized修改,所以是线程安全的,可用于多线程环境

与其他的映射集一样,Hashtable中也存在哈希碰撞(哈希冲突)的情况,解决方法是拉链法,即哈希桶数组加链表,其中链表 是单向的。从源码可以看到其实链表中节点是一个内部类Entry,继承了接口Map.Entry。包含了键的哈希值,键和值以及下一个节点Entry的引用。实际上Entry就是用于存储键-值对映射的类,Hashtable内部存储数据的容器就是一个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;
  }
}

介绍

1.构造方法

//构建一个指定的初始容量和负载因子的Hashtable
public Hashtable(int initialCapacity, float loadFactor) {}
//构建一个指定初始容量和默认负载因子为0.75的Hashtable
public Hashtable(int initialCapacity) {}
//构建一个默认初始容量为11,默认负载因子为0.75的Hashtable.
public Hashtable() {}
//构建一个与指定Map具有相同映射关系的Hashtable
public Hashtable(Map<? extends K, ? extends V> t) {}

2.内部变量

//Hashtable用于保存键-值对映射的数组
private transient Entry<?,?>[] table;
//Hashtable中键-值对映射数量
private transient int count;
//阈值(capacity*loadFactor),Hashtable的实际元素数量超过此值将会扩容
private int threshold;
//负载因子
private float loadFactor;
//Hashtable修改的次数,用于fail-fast机制
private transient int modCount = 0;

对于Hashtable中几个变量说明一下:

table是Hashtable用于存储数据的容量,实际就是一个Entry类型数组,数组每个索引保存的是节点Entry,由于每个节点保存了后面节点的引用,所以实际上每个索引位置都是一条单向链表。

thresold是阈值,通过capacity乘以loadFactor得到的,容量超过此值时将会扩容为原先的2倍+1。

loadFactor是负载因子,表示的是哈希桶数组在扩容之前键-值对的充满程度。默认值是0.75。

modCount是用来记录修改的次数,任何对Hashtable的修改都会导致ModCount++,使用迭代器进行迭代时会将ModCount值赋值给expectedModCount。在迭代过程中会判断modCount是否等于expectedModCount。如果不等,说明在迭代过程中其他线程修改了Hashtable,就会抛出ConcurrentModificationException异常。所谓的是fail-fast机制。

3.内部方法

//返回Hashtable中键的数量
public synchronized int size() {}
//如果Hashtable中不包含任何的键-值映射,将会返回true.
public synchronized boolean isEmpty() {}
//返回迭代Hashtable中所有键的Enumeration对象。
public synchronized Enumeration<K> keys() {}
//返回迭代Hashtable中所有值的Enumeration对象。
public synchronized Enumeration<V> elements() {}
//如果Hashtable中包含指定的值,将会返回true.如果指定的值value为null时,将会抛出NullPointerException异常。
public synchronized boolean contains(Object value) {}
//如果Hashtable包含指定值,将会返回true.如果指定值为null,将抛出NullPointerException异常。
public boolean containsValue(Object value) {}
//如果Hashtable中包含指定的键,将返回true.如果将为null,将抛出NullPointerException异常
public synchronized boolean containsKey(Object key) {}
//返回Hashtable中指定键key对应映射的值.如果指定键为null,将会抛出NullPointerException异常
public synchronized V get(Object key) {}
//将指定的键-值对映射添加到Hashtable。如果指定的"key-value"对映射中其中一个为null,将抛出NullPointerException异常。
public synchronized V put(K key, V value) {}
//从Hashtable中移除指定键对应的键-值对映射.如果指定的键为null,将会抛出NullPointerException异常
public synchronized V remove(Object key) {}
//将映射集合t中所有的键-值对映射添加到Hashtable中.如果指定映射集合t为null,将会抛出NullPointerException异常
public synchronized void putAll(Map<? extends K, ? extends V> t) {}
//清空Hastable
public synchronized void clear() {}
//创建Hashtable的浅度复制
public synchronized Object clone() {}
//返回Hashtable对象的字符串表现形式
public synchronized String toString() {}
//返回Hashtable中所有的键集合set
public Set<K> keySet() {}
//返回Hashtable中所有键-值对的集合Set
public Set<Map.Entry<K,V>> entrySet() {}
//返回Hashtable的值集合
public Collection<V> values() {}
//此Hashtable是否与指定对象o相等
public synchronized boolean equals(Object o) {}
//计算Hashtable中所有Entry哈希值的总和。
public synchronized int hashCode() {}
//返回Hashtable中指定键key对应的值value,如果value为null,返回指定的默认值defaultValue
public synchronized V getOrDefault(Object key, V defaultValue) {}
//对这个Map中所有的键和值执行action.
public synchronized void forEach(BiConsumer<? super K, ? super V> action) {}
//用键-值对在给指定函数上的执行结果替换键-值对的值.
public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {}
//Hashtable中键没有映射关系情况下与指定的值进行关联.
public synchronized V putIfAbsent(K key, V value) {}
//从Hashtable中移除与指定key和指定value同时相等的键-值对映射
public synchronized boolean remove(Object key, Object value) {}
//如果Hashtable中存在与指定键和指定值oldValue相等的映射,用newValue替换映射的值
public synchronized boolean replace(K key, V oldValue, V newValue) {}
//如果Hashtable中存在于指定键的映射,用指定的value替换映射的值
public synchronized V replace(K key, V value) {}
//如果指定key不存在映射关系,根据key计算出的函数值,将key与函数值进行关联.
public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {}
//如果Hashtable中存在指定键key的映射,根据key和key映射的值计算出的函数值,函数值不为空时,将key与函数值关联.
//函数值为空时,将会删除指定键key的映射
public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {}
//如果Hashtable中存在指定键key的映射,根据key和key映射的值计算出的函数值,函数值不为空时,将key与函数值关联.函数值为空时,删除指定键key的映射;
//如果Hashtable中不存在指定键的映射,当函数值不为空时,向Hashtable中添加键-函数值映射
public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {}
//如果Hashtable中存在指定键key的映射时,根据键对应的值和指定的值计算函数表达式的函数值,如果函数值为空,删除键的映射,如果函数值不为空,将键-函数值关联。
//如果Hashtble中不存在指定键key的映射时,并且指定的值value不为null,将键-指定值value映射添加到Hashtable中
public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {}

源码分析(jdk1.8)

关于源码几点说明

1.Hashtable的键和值都不能为null,如果为null时,大部分方法里面处理方式会判断如果值为null,将会抛出NullPointerException异常。如果键为null时,调用key.hashCode()方法将会抛出NullPointerException异常。

2.key.hashCode()获取键的哈希值,哈希值与数组长度取模是直接通过 (hash & 0x7FFFFFFF) % tab.length,由于计算机处理数据是基于二进制的,算术运算术"%"效率较低。

3.哈希桶数组中元素的数量超过阈值,将会扩容,根据int newCapacity = (oldCapacity << 1) + 1计算得到扩容后容量=原先容量*2+1。

4.大部分的方法都有定位键在哈希桶数组的位置代码,大致思路:首先是获取键的哈希值,然后键的哈希值与数组长度取模,得到在数组中的索引位置,遍历索引位置的链表来定位节点(目标节点Entry与指定键具有相同的hash值和键值)

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

     //Hashtable用于保存键-值对映射的数组
     //每个Entry内部保存了下个节点next引用,所以数组table中所有索引位置都是单向链表。
    private transient Entry<?,?>[] table;

    //Hashtable中键-值对映射数量
    private transient int count;

    //阈值(capacity*loadFactor),Hashtable的实际元素数量超过此值将会扩容
    private int threshold;

   //负载因子
    private float loadFactor;

    //Hashtable的结构被修改的次数(即键-值对映射数量变化或者rehash操作)
    //变量用于fail-fast机制
    private transient int modCount = 0;

    //序列化版本号
    private static final long serialVersionUID = 1421746759512286392L;

    //构建一个指定的初始容量和负载因子的Hashtable
    public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
        //指定容量为0时,会被赋值为1
        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        //创建Entry类型的数组
        table = new Entry<?,?>[initialCapacity];
        //获取阈值的大小(initialCapacity * loadFactor)
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }

    //构建一个指定初始容量和负载因子默认值为0.75的Hashtable.
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

    //构建一个默认初始容量为11,负载因子默认值为0.75的Hashtable.
    public Hashtable() {
        this(11, 0.75f);
    }

    //构建一个与指定Map具有相同映射关系的Hashtable
    //如果指定Map为null,将会抛出NullPointerException异常。
    public Hashtable(Map<? extends K, ? extends V> t) {
      //首先会创建一个负载因子是0.75,容量能容纳指定映射的Hashtable
        this(Math.max(2*t.size(), 11), 0.75f);
        //然后调用putAll()方法将映射t中键-值对映射存储到Hashtable中
        putAll(t);
    }

    //返回Hashtable中键的数量
    public synchronized int size() {
        return count;
    }

    //如果Hashtable中不包含任何的键-值映射,将会返回true.
    public synchronized boolean isEmpty() {
        return count == 0;
    }

    //返回迭代Hashtable中所有键的Enumeration对象。
    public synchronized Enumeration<K> keys() {
        return this.<K>getEnumeration(KEYS);
    }

    //返回迭代Hashtable中所有值的Enumeration对象。
    public synchronized Enumeration<V> elements() {
        return this.<V>getEnumeration(VALUES);
    }

    //如果Hashtable中包含指定的值,将会返回true.
    //如果指定的值value为null时,将会抛出NullPointerException异常。
    //此方法比containKey方法操作成本高
    public synchronized boolean contains(Object value) {  
      if (value == null) {
            throw new NullPointerException();
        }

        Entry<?,?> tab[] = table;
        //反向迭代数组table
        for (int i = tab.length ; i-- > 0 ;) {
          //正向迭代table指定索引位置的单向链表
            for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
              //如果链表中节点Entry的值等于value,返回true.
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }

    //如果Hashtable包含指定值,将会返回true.
    //如果指定值为null,将抛出NullPointerException异常。
    public boolean containsValue(Object value) {
        return contains(value);
    }

    //如果Hashtable中包含指定的键,将返回true.
    //如果将为null,将抛出NullPointerException异常
    public synchronized boolean containsKey(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        //键的hash值取模,得到数组table中索引位置
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //迭代指定索引位置index的链表
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
          //如果链表中存在与指定键具有相同的hash值和键值的节点Entry,返回true.
            if ((e.hash == hash) && e.key.equals(key)) {
                return true;
            }
        }
        return false;
    }

    //返回Hashtable中指定键key对应映射的值
    //如果指定键为null,将会抛出NullPointerException异常
    public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        //指定键key的hash值
        int hash = key.hashCode();
       //键的hash值与数组长度取模,得到在数组table中索引位置
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //迭代指定索引位置index的链表
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
          //如果链表中存在与指定键具有相同的hash值和键值的节点Entry,返回节点的值.
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;
    }

    //可分配数组的最大值,虚拟机在数组中预留一些空间,如果数组的容量超过此最大值,将会引起OutOfMemoryError
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //Hashtable扩容并调整内部元素位置
    //此方法会在键数量超过阈值(capacity*loadFactor)将会自动调整
    //容量会变为原先的2倍+1
    @SuppressWarnings("unchecked")
    protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;
        //扩容后的容量不能超过最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        //新建Entry类型的数组
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
        //修改次数+1
        modCount++;
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        table = newMap;
        //反向迭代数组
        for (int i = oldCapacity ; i-- > 0 ;) {
          //遍历索引位置的链表
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;
                //键-值对Entry的哈希值与扩容后的容量取模,得到在新数组中的索引位置
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                //将后面添加的节点添加到之前的节点前面
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }
    
    //向Hashtable中添加键-值对映射
    private void addEntry(int hash, K key, V value, int index) {
        //修改次数+1
        modCount++;

        Entry<?,?> tab[] = table;
        //如果Hashtable中实际容量超过了阈值,会调整Hashtable的大小
        //并且会重新计算索引位置index
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();
            
            tab = table;
            //键的hash值
            hash = key.hashCode();
            //键的hash值与数组长度取模,得到在Hashtable中的索引位置
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
        //获取指定索引位置的首节点
        Entry<K,V> e = (Entry<K,V>) tab[index];
        //新建节点,将新节点添加到已存在节点的前面
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }

    //将指定的键-值对映射添加到Hashtable。
    //如果指定的"key-value"对映射中其中一个为null,将抛出NullPointerException异常。
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        //指定键的hash值
        int hash = key.hashCode();
        //键的hash值与数组长度取模,得到在数组table中的索引位置
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        //遍历指定索引位置的链表
        for(; entry != null ; entry = entry.next) {
          //如果链表中存在与指定键的hash值和key相同的节点Entry
            if ((entry.hash == hash) && entry.key.equals(key)) {
              //获取原先的节点entry的值
                V old = entry.value;
                //用指定的值value替换原先值
                entry.value = value;
                //返回原先值
                return old;
            }
        }
        //走到这里表明在指定索引位置上的链表中不存在与指定的键-值对映射
       //向Hashtable指定索引位置添加节点
        addEntry(hash, key, value, index);
        return null;
    }

    //从Hashtable中移除指定键对应的键-值对映射,如果不存在指定键,方法不会做任何工作
    //方法将返回指定键key对应的值,不存在键-值映射,将返回null
    //如果指定的键为null,将会抛出NullPointerException异常
    public synchronized V remove(Object key) {
        Entry<?,?> tab[] = table;
        //键的hash值
        int hash = key.hashCode();
        //键的hash值与数组长度取模,得到在数组table中的索引位置
        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) {
          //如果链表中存在与指定键具有相同的hash值和键值的节点,删除节点
            if ((e.hash == hash) && e.key.equals(key)) {
                modCount++;
                //将当前节点的上个节点后驱指针指向当前节点的下个节点
                if (prev != null) {
                    prev.next = e.next;
                } else {
                  //如果是首节点,将下个节点直接存储到指定索引位置
                    tab[index] = e.next;
                }
                //元素数量自减
                count--;
                //获取节点的值value
                V oldValue = e.value;
                //将节点的值置为null,垃圾回收
                e.value = null;
                //返回原先值
                return oldValue;
            }
        }
        return null;
    }

    //将映射集合t中所有的键-值对映射添加到Hashtable中
    //Hashtable存在与映射集合t相同的键-值对映射,将会用指定映射集合t中的映射替换Hashtable中的映射
    //如果指定映射集合t为null,将会抛出NullPointerException异常
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
      //遍历映射集合t,将所有键-值对映射添加到Hashtable
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            put(e.getKey(), e.getValue());
    }

    //清空Hastable
    public synchronized void clear() {
        Entry<?,?> tab[] = table;
        //修改次数自增
        modCount++;
        //遍历整个数组,将所有索引位置的元素置为null
        for (int index = tab.length; --index >= 0; )
            tab[index] = null;
        //元素数量置为0
        count = 0;
    }

    //创建Hashtable的浅度复制
    public synchronized Object clone() {
        try {
            Hashtable<?,?> t = (Hashtable<?,?>)super.clone();
            t.table = new Entry<?,?>[table.length];
            for (int i = table.length ; i-- > 0 ; ) {
                t.table[i] = (table[i] != null)
                    ? (Entry<?,?>) table[i].clone() : null;
            }
            t.keySet = null;
            t.entrySet = null;
            t.values = null;
            t.modCount = 0;
            return t;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

    //返回Hashtable对象的字符串表现形式
    public synchronized String toString() {
        int max = size() - 1;
        if (max == -1)
            return "{}";

        StringBuilder sb = new StringBuilder();
        Iterator<Map.Entry<K,V>> it = entrySet().iterator();

        sb.append('{');
        //遍历键-值对Entry,将键和值都添加到格式中
        for (int i = 0; ; i++) {
            Map.Entry<K,V> e = it.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key.toString());
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value.toString());
            
            if (i == max)
                return sb.append('}').toString();
            sb.append(", ");
        }
    }

    //返回Enumeration对象
    private <T> Enumeration<T> getEnumeration(int type) {
        if (count == 0) {
            return Collections.emptyEnumeration();
        } else {
            return new Enumerator<>(type, false);
        }
    }
    
    //返回Iterator对象
    private <T> Iterator<T> getIterator(int type) {
        if (count == 0) {
            return Collections.emptyIterator();
        } else {
            return new Enumerator<>(type, true);
        }
    }

    // Views
    //Hashtable中所有键的集合,由于键本身不会重复,所以是Set集合
    private transient volatile Set<K> keySet;
    //Hashtable中所有键-值的集合,键-值对不会重复,所以是Set集合
    private transient volatile Set<Map.Entry<K,V>> entrySet;
    //Hashtabe中所有值的集合,值没有要求,可以重复
    private transient volatile Collection<V> values;

    //返回Hashtable中所有的键集合set
    //此set集合支持键的移除操作(Iterator.remove,Set.remove,removeAll,retainAll,clear)
    //不支持add或者addAll操作,移除操作将直接影响Hashtable。
    public Set<K> keySet() {
        if (keySet == null)
            keySet = Collections.synchronizedSet(new KeySet(), this);
        return keySet;
    }

    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();
        }
    }

    //返回Hashtable中所有键-值对的集合Set
   // 此set集合支持键的移除操作(Iterator.remove,Set.remove,removeAll,retainAll,clear),
    //不支持add或者addAll操作。移除操作将直接影响Hashtable
    public Set<Map.Entry<K,V>> entrySet() {
        if (entrySet==null)
            entrySet = Collections.synchronizedSet(new EntrySet(), this);
        return entrySet;
    }

    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return getIterator(ENTRIES);
        }
        
        //向键-值对集合中添加节点Entry
        public boolean add(Map.Entry<K,V> o) {
            return super.add(o);
        }
        //键-值对集合是否包含指定元素o
        //比较的是Entry的hash值和Entry本身是否相等(包含键和值都相等)
        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;
            //遍历指定索引位置index处的链表,找到与Entry和Entry的哈希值相同的节点
            for (Entry<?,?> e = tab[index]; e != null; e = e.next)
                if (e.hash==hash && e.equals(entry))
                    return true;
            return false;
        }
        
        //从键-值对集合中移除指定元素o
        //如果Entry的hash值和Entry值(包含键和值)都相等,移除命中元素
        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];
            //遍历指定索引位置的链表,如果Entry的hash值和Entry值(包含键和值)都相等,移除命中元素
            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();
        }
    }

    //返回Hashtable的值集合
    //集合支持键的移除操作(Iterator.remove,Set.remove,removeAll,retainAll,clear),
    //不支持add或者addAll操作。移除操作将会影响Hashtable
    public Collection<V> values() {
        if (values==null)
            values = Collections.synchronizedCollection(new ValueCollection(),
                                                        this);
        return values;
    }

    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();
        }
    }

    // Comparison and hashing
    //此Hashtable是否与指定对象o相等
    public synchronized boolean equals(Object o) {
        //同一个引用,直接返回true
        if (o == this)
            return true;
        //不是同一个类型,返回false
        if (!(o instanceof Map))
            return false;
        Map<?,?> t = (Map<?,?>) o;
        //元素数量不相同,返回false
        if (t.size() != size())
            return false;

        try {
          //遍历Hashtable,查看所有的键-值对映射是否也存在于指定对象o中。
            Iterator<Map.Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Map.Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(t.get(key)==null && t.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(t.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

    //计算Hashtable中所有Entry哈希值的总和。
    //如果Hashtable中元素的数量是0或者负载因子是小于0,返回0
    //否则将返回所有Entry的哈希值的总和
    public synchronized int hashCode() {
        /*
         * This code detects the recursion caused by computing the hash code
         * of a self-referential hash table and prevents the stack overflow
         * that would otherwise result.  This allows certain 1.1-era
         * applets with self-referential hash tables to work.  This code
         * abuses the loadFactor field to do double-duty as a hashCode
         * in progress flag, so as not to worsen the space performance.
         * A negative load factor indicates that hash code computation is
         * in progress.
         */
        int h = 0;
        if (count == 0 || loadFactor < 0)
            return h;  // Returns zero

        loadFactor = -loadFactor;  // Mark hashCode computation in progress
        Entry<?,?>[] tab = table;
        //迭代Hashtable,将所有Entry的哈希值相加
        for (Entry<?,?> entry : tab) {
            while (entry != null) {
                h += entry.hashCode();
                entry = entry.next;
            }
        }

        loadFactor = -loadFactor;  // Mark hashCode computation complete

        return h;
    }

    @Override
    //返回Hashtable中指定键key对应的值value,如果value为null,返回指定的默认值defaultValue
    public synchronized V getOrDefault(Object key, V defaultValue) {
        V result = get(key);
        return (null == result) ? defaultValue : result;
    }

    @SuppressWarnings("unchecked")
    @Override
  //对这个Map中所有的键和值执行action操作.
    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);     // explicit check required in case
                                            // table is empty.
        final int expectedModCount = modCount;

        Entry<?, ?>[] tab = table;
        //遍历Entry数组
        for (Entry<?, ?> entry : tab) {
            while (entry != null) {
                action.accept((K)entry.key, (V)entry.value);
                entry = entry.next;
                //检查并发修改
                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    //用键-值对在给指定函数上的执行结果替换键-值对的值.
    public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);     // explicit check required in case
                                              // table is empty.
        final int expectedModCount = modCount;

        Entry<K, V>[] tab = (Entry<K, V>[])table;
        //遍历数组,用键和值在指定函数上的执行结果替换值
        for (Entry<K, V> entry : tab) {
            while (entry != null) {
                entry.value = Objects.requireNonNull(
                    function.apply(entry.key, entry.value));
                entry = entry.next;
                //检查并发修改
                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }

    @Override
  //Hashtable中键没有映射关系情况下与指定的值进行关联.
    public synchronized V putIfAbsent(K key, V value) {
        Objects.requireNonNull(value);

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for (; entry != null; entry = entry.next) {
          //存在与指定键具有相同的hash值和键值的节点,值为空时,将键与指定的值value关联,不为空时,返回原先的值
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                if (old == null) {
                    entry.value = value;
                }
                return old;
            }
        }
        //将关联后的键-值对添加到Hashtable中
        addEntry(hash, key, value, index);
        return null;
    }

    @Override
    //从Hashtable中移除与指定key和指定value同时相等的键-值对映射
    public synchronized boolean remove(Object key, Object value) {
        Objects.requireNonNull(value);

        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) {
          //如果键的哈希值,键和值与指定的key和value都相同,删除命中节点
            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
                modCount++;
                //将当前节点的上个节点后驱指针指向当前节点的下个节点
                if (prev != null) {
                    prev.next = e.next;
                } else {
                  //如果是首节点,将下个节点存储到索引位置
                    tab[index] = e.next;
                }
                count--;
                e.value = null;
                return true;
            }
        }
        return false;
    }

    @Override
    //如果Hashtable中存在与指定键和指定值oldValue相等的映射,用newValue替换映射的值
    public synchronized boolean replace(K key, V oldValue, V newValue) {
        Objects.requireNonNull(oldValue);
        Objects.requireNonNull(newValue);
        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 (; e != null; e = e.next) {
          //如果键的哈希值和键值与指定键key的相同
          //并且值与指定的值oldValue相同,则用newValue替换指定键对应的值
            if ((e.hash == hash) && e.key.equals(key)) {
                if (e.value.equals(oldValue)) {
                    e.value = newValue;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

    @Override
    //如果Hashtable中存在于指定键的映射,用指定的value替换映射的值
    public synchronized V replace(K key, V value) {
        Objects.requireNonNull(value);
        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 (; e != null; e = e.next) {
          //如果键的哈希值,键值与指定键的相同,用指定的值value替换映射的值
            if ((e.hash == hash) && e.key.equals(key)) {
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
        return null;
    }

    @Override
  //如果指定key不存在映射关系,根据key计算出的函数值,将key与函数值进行关联.
    public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
        Objects.requireNonNull(mappingFunction);

        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 (; e != null; e = e.next) {
            if (e.hash == hash && e.key.equals(key)) {
                // Hashtable not accept null value
                return e.value;
            }
        }
        //键不存在映射时,根据key计算函数表达式的函数值,并将函数值和键添加到Hashtable中
        V newValue = mappingFunction.apply(key);
        if (newValue != null) {
            addEntry(hash, key, newValue, index);
        }

        return newValue;
    }

    @Override
  //如果Hashtable中存在指定键key的映射,根据key和key映射的值计算出的函数值,函数值不为空时,将key与函数值关联.
    //函数值为空时,将会删除指定键key的映射
    public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);

        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.key.equals(key)) {
              //根据键和值计算函数表达式的值
                V newValue = remappingFunction.apply(key, e.value);
                //函数值为空时,删除键-值对映射
                if (newValue == null) {
                    modCount++;
                    //不是首节点,将当前节点上个节点的后驱指针指向当前节点的下个节点
                    if (prev != null) {
                        prev.next = e.next;
                    } else {
                    //将首节点的下个节点存储到索引位置
                        tab[index] = e.next;
                    }
                    count--;
                 //函数不为空时,将键与函数值关联
                } else {
                    e.value = newValue;
                }
                return newValue;
            }
        }
        return null;
    }

    @Override
  //如果Hashtable中存在指定键key的映射,根据key和key映射的值计算出的函数值,函数值不为空时,将key与函数值关联.函数值为空时,删除指定键key的映射;
    //如果Hashtable中不存在指定键的映射,当函数值不为空时,向Hashtable中添加键-函数值映射
    public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);

        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 && Objects.equals(e.key, key)) {
                V newValue = remappingFunction.apply(key, e.value);
                //函数值为空时,将键-对映射映射删除
                if (newValue == null) {
                    modCount++;
                    //不是首节点,将当前节点上个节点的后驱指针指向当前节点的下个节点
                    if (prev != null) {
                        prev.next = e.next;
                    } else {
                      //将首节点的下个节点存储到索引位置
                        tab[index] = e.next;
                    }
                    count--;
                } else {
                  //否则将键与函数值进行关联映射
                    e.value = newValue;
                }
                return newValue;
            }
        }
        
        V newValue = remappingFunction.apply(key, null);
        if (newValue != null) {
            addEntry(hash, key, newValue, index);
        }

        return newValue;
    }

    @Override
  //如果Hashtable中存在指定键key的映射时,根据键对应的值和指定的值计算函数表达式的函数值,如果函数值为空,删除键的映射,如果函数值不为空,将键-函数值关联。
    //如果Hashtble中不存在指定键key的映射时,并且指定的值value不为null,将键-指定值value映射添加到Hashtable中
    public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);

        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.key.equals(key)) {
                V newValue = remappingFunction.apply(e.value, value);
                //函数值为null时,将键的映射删除
                if (newValue == null) {
                    modCount++;
                    //不是首节点,将当前节点上个节点的后驱指针指向当前节点的下个节点
                    if (prev != null) {
                        prev.next = e.next;
                    } else {
                      //将首节点的下个节点存储到索引位置
                        tab[index] = e.next;
                    }
                    count--;
                    //函数值不为null时,将键与函数关联
                } else {
                    e.value = newValue;
                }
                return newValue;
            }
        }
        //hashtable中不存在指定键的映射,并且指定值value不为空
        //向Hashtable中添加键-指定值value映射
        if (value != null) {
            addEntry(hash, key, value, index);
        }

        return value;
    }

    //将Hashtable的状态写到流中
    //依次写入Hashtable的容量,实际元素的数量,以及所有的键-值对映射
    private void writeObject(java.io.ObjectOutputStream s)
            throws IOException {
        Entry<Object, Object> entryStack = null;

        synchronized (this) {
            // Write out the threshold and loadFactor
            s.defaultWriteObject();

            // Write out the length and count of elements
            //写入数组长度和元素数量
            s.writeInt(table.length);
            s.writeInt(count);

            // Stack copies of the entries in the table
            //遍历数组,将所有索引位置的链表串成一个单链表
            for (int index = 0; index < table.length; index++) {
                Entry<?,?> entry = table[index];
                //将指定索引位置的链表重新串起来
                while (entry != null) {
                    entryStack =
                        new Entry<>(0, entry.key, entry.value, entryStack);
                    entry = entry.next;
                }
            }
        }

        // Write out the key/value objects from the stacked entries
        //遍历上面单链表,将链表中所有节点的键和值全部写到流中
        while (entryStack != null) {
            s.writeObject(entryStack.key);
            s.writeObject(entryStack.value);
            entryStack = entryStack.next;
        }
    }

    //从流中读取数据,重建Hashtable(反序列化)
    //依次从流中读取阈值和负载因子、数组容量、元素数量,元素构建Hashtable
    private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException
    {
        // Read in the threshold and loadFactor
        s.defaultReadObject();

        // Validate loadFactor (ignore threshold - it will be re-computed)
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new StreamCorruptedException("Illegal Load: " + loadFactor);

        // Read the original length of the array and number of elements
        //读取数组的长度和元素的数量
        int origlength = s.readInt();
        int elements = s.readInt();

        // Validate # of elements
        if (elements < 0)
            throw new StreamCorruptedException("Illegal # of Elements: " + elements);

        // Clamp original length to be more than elements / loadFactor
        // (this is the invariant enforced with auto-growth)
        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);

        // Compute new length with a bit of room 5% + 3 to grow but
        // no larger than the clamped original length.  Make the length
        // odd if it's large enough, this helps distribute the entries.
        // Guard against the length ending up zero, that's not valid.
        int length = (int)((elements + elements / 20) / loadFactor) + 3;
        if (length > elements && (length & 1) == 0)
            length--;
        length = Math.min(length, origlength);

        // Check Map.Entry[].class since it's the nearest public type to
        // what we're actually creating.
        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
        table = new Entry<?,?>[length];
        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
        count = 0;

        // Read the number of elements and then all the key/value objects
        for (; elements > 0; elements--) {
            @SuppressWarnings("unchecked")
                K key = (K)s.readObject();
            @SuppressWarnings("unchecked")
                V value = (V)s.readObject();
            // sync is eliminated for performance
            reconstitutionPut(table, key, value);
        }
    }

    //readObject方法调用
    private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
        throws StreamCorruptedException
    {
        if (value == null) {
            throw new java.io.StreamCorruptedException();
        }
        // Makes sure the key is not already in the hashtable.
        // This should not happen in deserialized version.
        //键的哈希值
        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.key.equals(key)) {
                throw new java.io.StreamCorruptedException();
            }
        }
        // Creates the new entry.
        @SuppressWarnings("unchecked")
        //获取指定索引处的节点,新建节点的后驱指针指向此节点
            Entry<K,V> e = (Entry<K,V>)tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }

    /**
     * Hashtable bucket collision list entry
     */
    //Hashtable中链表的节点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;
        }
        
        //向节点Entry设置值,如果value为null,将抛出NullPointerException异常
        public V setValue(V value) {
            if (value == null)
                throw new NullPointerException();

            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }
        
        //Entry是Hashtable中索引位置的链表中节点
        //此Entry与指定的对象o是否相等,实际比较的是键和值是否都相等
        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();
        }
    }

    // Types of Enumerations/Iterations
    private static final int KEYS = 0;
    private static final int VALUES = 1;
    private static final int ENTRIES = 2;

    //用于迭代Hashtable的内部类,实现了Enumeration和Iterator接口
    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
        Entry<?,?>[] table = Hashtable.this.table;
        int index = table.length;
        Entry<?,?> entry;
        Entry<?,?> lastReturned;
        int type;

        //表示的是Enumrator是一个迭代器Iterator类型还是枚举Enumeraion类型,如果是true,表示的是Iterator
        boolean iterator;

        //fail-fast机制,Hashtable的迭代器期望得到modCount值,如果此值在迭代时发生了改变
        //表明有并发修改的情况
        protected int expectedModCount = modCount;

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

        //反向迭代,找到不为null的Entry
        public boolean hasMoreElements() {
            Entry<?,?> e = entry;
            int i = index;
            Entry<?,?>[] t = table;
            /* Use locals for faster loop iteration */
            //反向迭代,找到不为null的节点时,跳出循环
            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 */
            //反向迭代,找到不为null的节点时,跳出循环
            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
        //迭代的方法,实际会调用hasMoreElements()
        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) {
              //tab指向是的Hashtable中的数组
                Entry<?,?>[] tab = Hashtable.this.table;
                //lastReturned是调用next()方法进行赋值,这里与数组长度取模得到在数组中索引位置
                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

1.遍历Hashtable的键-值对。

通过调用entrySet()方法获取Hashtable的键-值对映射集合Set,然后迭代Set集合获取key和value。

2.遍历Hashtable的键。

调用keySet()方法获取Hashtable的键集合Set,然后迭代Set集合获取键,通过调用get()方法获取指定键对应的值。

3.遍历Hashtable的值。

调用values()方法获取Hashtable的值集合Collection,迭代获取所有值。

4.通过Enumeration来获取Hashtable键和值

分别调用方法keys()和elements()方法来获取Hashtable的键和值。

public class AIteratorHashtable {
  public static void main(String[] args) {
    Hashtable<String,Integer> map = new Hashtable<>();
    map.put("first", 1);
    map.put("second",2);
    map.put("third", 3);
    map.put("forth", 4);
    iteratorHashtableByEntrySet(map);
    iteratorHashtableByKeySet(map);
    iteratorHashtableByValueSet(map);
    iteratorHashtableByEnumeration(map);
  }
  
  //第一种方式迭代键-值对
  private static void iteratorHashtableByEntrySet(Map<String,Integer> map) {
    Set<Entry<String, Integer>> entrySet = map.entrySet();
    //迭代器
    Iterator<Entry<String, Integer>> iterator = entrySet.iterator();
    while(iterator.hasNext()) {
      Entry<String, Integer> entry = iterator.next();
      System.out.println(entry.getKey()+"------"+entry.getValue());
    }
    //foreach循环
    for(Entry<String,Integer> entry:entrySet) {
      System.out.println(entry.getKey()+"------"+entry.getValue());
    }
  }
  
  //第二种方式迭代键集合
  private static void iteratorHashtableByKeySet(Map<String,Integer> map) {
    Set<String> keySet = map.keySet();
    //迭代器
    Iterator<String> iterator = keySet.iterator();
    while(iterator.hasNext()) {
      String key = iterator.next();
      System.out.println(key+"-------"+map.get(key));
    }
    //foreach循环
    for(String key:keySet) {
      System.out.println(key+"---------"+map.get(key));
    }
  }
  //第三种方式迭代值
  private static void iteratorHashtableByValueSet(Map<String,Integer> map) {
    Collection<Integer> values = map.values();
    //迭代器
    Iterator<Integer> iterator = values.iterator();
    while(iterator.hasNext()) {
      System.out.println(iterator.next());
    }
    //forearch循环
    for(Integer in:values) {
      System.out.println(in);
    }
  }
  
  //第四种方式迭代值和值
  private static void iteratorHashtableByEnumeration(Hashtable<String,Integer> map) {
    Enumeration<String> keys = map.keys();
    while(keys.hasMoreElements()) {
      System.out.println(keys.nextElement());
    }
    Enumeration<Integer> elements = map.elements();
    while(elements.hasMoreElements()) {
      System.out.println(elements.nextElement());
    }
  }
}

Hashtable与HashMap的区别

1.Hashtable自jdk1.0引入的,继承了Dictionary抽象类,HashMap是jdk1.2引入的,继承了AbstractMap抽象类,它们都继承了Map接口。

2.Hashtable中大部分方法都使用了synchronized修改,线程是安全的。而HashMap是线程不安全的。

3.Hashtable不允许存储null值和null键,这在HashMap是可以的。

4.Hashtable扩容后的容量是原先的2倍+1,而HashMap是原先容量2倍。

5.jdk1.8版本HashMap作为了很多优化,默认初始容量是16,扩容后的容量一定是2^{x},计算索引位置是通过位运算(n-1)&key.hash(n是数组长度)得到的。而Hashtable默认初始容量是11,通过算术运算符(hash & 0x7FFFFFFF) % tab.length来计算索引位置,此外HashMap引入了红黑树,链表的节点数量超过8个,会将链表转变成红黑树。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值