Hashtable源码分析。

版权声明:转载需说明出处。 https://blog.csdn.net/en_joker/article/details/88868255
/**
 * 此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。
 * 
 * 为了成功地在哈希表中存储和获取对象,用作键的对象必须实现 hashCode 方法和 equals 方法。
 * 
 * Hashtable 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为
 * open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子
 * 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash
 * 方法的具体细节则依赖于该实现。
 * 
 * 通常,默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable
 * 操作中,包括 get 和 put 操作,都反映了这一点)。
 * 
 * 初始容量主要控制空间消耗与执行 rehash 操作所需要的时间损耗之间的平衡。如果初始容量大于 Hashtable 所包含的最大条目数除以加载因子,则永远
 * 不会发生 rehash 操作。但是,将初始容量设置太高可能会浪费空间。
 * 
 * 如果很多条目要存储在一个 Hashtable 中,那么与根据需要执行自动 rehashing
 * 操作来增大表的容量的做法相比,使用足够大的初始容量创建哈希表或许可以更有效地插入条目。
 * 
 *
 */
public class Hashtable<K, V> extends Dictionary<K,V>
	implements Map<K,V>, Cloneable, java.io.Serializable{
	/*
	 * 继承Dictionary类,实现了Map接口。
	 * Map是“key-value键值对”接口,
	 * Dictionary是声明了操作“键值对”函数接口的抽象类。
	 */
	
	/**
	 * 存储键值对对象的桶数组
	 */
	private transient Entry<?,?>[] table;
	/**
	 * 哈希表中条目的总数。
	 */
	private transient int count;
	/**
	 * 当表的大小超过此阈值时,将重新哈希表。
	 * threshold的值=容量*加载因子。
	 */
    private int threshold;
    /**
     * 哈希表的加载因子。
     */
    private float loadFactor;
    /**
     * hashtable被改变的次数,用来实现fail-fast机制
     */
    private transient int modCount = 0;
    /**
     * 使用JDK 1.0.2中的serialVersionUID实现互操作性
     */
    private static final long serialVersionUID = 1421746759512286392L;
    
    /**
     * 用指定初始容量和指定加载因子构造一个新的空哈希表。
     * @param initialCapacity	哈希表的初始容量。
     * @param loadFactor	哈希表的加载因子。
     */
    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);

        if (initialCapacity==0)
            initialCapacity = 1; // 初始容量最小值为1
        this.loadFactor = loadFactor;
        table = new Entry<?,?>[initialCapacity]; // 创建桶数组
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }
    
    /**
     * 用指定初始容量和默认的加载因子 (0.75) 构造一个新的空哈希表。 
     * @param initialCapacity	 哈希表的初始容量
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
    
    /**
     * 用默认的初始容量 (11) 和加载因子 (0.75) 构造一个新的空哈希表。
     */
    public Hashtable() {
        this(11, 0.75f);
    }
    
    /**
     * 构造一个与给定的 Map 具有相同映射关系的新哈希表。
     * 该哈希表是用足以容纳给定 Map 中映射关系的初始容量和默认的加载因子(0.75)创建的。
     * @param t	其映射关系将存放在此映射中的映射。
     */
    public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);	// 将t的所有映射关系复制到此哈希表中
    }
    
    /**
     * 返回此哈希表中的键的数量。
     * 覆写Dictionary<K,V> 中的 size
     */
    public synchronized int size() {
        return count;
    }
    
    /**
     * 测试此哈希表是否没有键映射到值。
     * 覆写Dictionary<K,V> 中的 isEmpty
     */
    public synchronized boolean isEmpty() {
        return count == 0;
    }
    
    /**
     * 返回此哈希表中的键的枚举。
     * 覆写Dictionary<K,V> 中的 keys
     */
    public synchronized Enumeration<K> keys() {
        return this.<K>getEnumeration(KEYS);
    }
    
    /**
     * 返回此哈希表中的值的枚举。对返回的对象使用 Enumeration 方法,以便按顺序获取这些元素。
     * 覆写Dictionary<K,V> 中的 elements
     */
    public synchronized Enumeration<V> elements() {
        return this.<V>getEnumeration(VALUES);
    }
    
    /**
     * 测试此映射表中是否存在与指定值关联的键。
     * 此操作比 containsKey 方法的开销更大。
     * 注意,此方法在功能上等同于 containsValue 方法,
     * containValue 是 collection 框架中 Map 接口的一部分。 
     * @param value	要搜索的值
     * @return	当且仅当此哈希表中某个键映射到 value 参数(由 equals 方法确定)时,返回 true;否则返回 false。 
     */
    public synchronized boolean contains(Object value) {
        if (value == null) { // 如果该值为 null
            throw new NullPointerException();
        }

        Entry<?,?> tab[] = table;
        for (int i = tab.length ; i-- > 0 ;) {
            for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * 如果此 Hashtable 将一个或多个键映射到此值,则返回 true。
     * 注意,此方法在功能上等同于contains(它先于 Map 接口)。
     * 覆写 Map<K,V> 中的 containsValue
     */
    public boolean containsValue(Object value) {
        return contains(value);
    }
    
    /**
     * 测试指定对象是否为此哈希表中的键。
     * 覆写 Map<K,V> 中的 containsKey
     */
    public synchronized boolean containsKey(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;// 再根据hash值找到索引
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 
     * 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,
     * 则此方法返回 v;否则,返回 null。(最多只能有一个这样的映射。) 
     * 覆写 Dictionary<K,V> 中的 get
     */
    @SuppressWarnings("unchecked")
    public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();	
        int index = (hash & 0x7FFFFFFF) % tab.length;	// 再根据hash值找到索引
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {	// 遍历entry链
            if ((e.hash == hash) && e.key.equals(key)) {	// 若找到该键
                return (V)e.value;	// 返回对应的值
            }
        }
        return null;	// 否则返回null
    }
    
    /**
     * 要分配的数组的最大大小。
     * 一些vm在数组中保留一些头信息。
     * 试图分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    /**
     * 增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。
     * 当哈希表中的键的数量超出哈希表的容量和加载因子时,自动调用此方法。
     */
    @SuppressWarnings("unchecked")
    protected void rehash() {
        int oldCapacity = table.length;	// 记录旧容量
        Entry<?,?>[] oldMap = table;	// 记录旧的桶数组

        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;	// 新容量为老容量的2倍加1
        if (newCapacity - MAX_ARRAY_SIZE > 0) {	
            if (oldCapacity == MAX_ARRAY_SIZE)	// 容量不得超过约定的最大值
                // 继续使用MAX_ARRAY_SIZE桶运行
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];	// 创建新的数组

        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;

                int index = (e.hash & 0x7FFFFFFF) % newCapacity; // 根据hash值找到索引
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }
    
    /**
     * 加节点
     * @param hash	hash值
     * @param key	hash表的键
     * @param value	值
     * @param index	hash表中的存储位置
     */
    private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
        if (count >= threshold) {
            // 如果超过阈值,则重新哈希表
            rehash();	// 重新构建桶数组,并对数组中所有键值对重哈希,耗时!

            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;	// 这里是取模运算
        }

        // 创建新条目。
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];
        // 将新结点插到链表首部
        tab[index] = new Entry<>(hash, key, value, e); // 生成一个新结点
        count++;
    }
    
    /**
     * 将指定 key 映射到此哈希表中的指定 value。键和值都不可以为 null。 
     * 通过使用与原来的键相同的键调用 get 方法,可以获取相应的值。
     * 覆写 Dictionary<K,V> 中的 put
     */
    public synchronized V put(K key, V value) {
        // 确保值不为空
        if (value == null) {
            throw new NullPointerException();
        }

        // 确保键不在散列表中。
        Entry<?,?> tab[] = table;	
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;	// 通过hash值找到其存储位置
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {	// 遍历链表
            if ((entry.hash == hash) && entry.key.equals(key)) {	// 若键相同,则新值覆盖旧值
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

    /**
     * 从哈希表中移除该键及其相应的值。如果该键不在哈希表中,则此方法不执行任何操作。
     * 覆写 Dictionary<K,V> 中的 remove
     */
    public synchronized V remove(Object key) {
        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) {	// 遍历entry链
            if ((e.hash == hash) && e.key.equals(key)) {	// 找到指定键
                modCount++;
                if (prev != null) {	// 修改相关指针
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }
    
    /**
     * 将指定映射的所有映射关系复制到此哈希表中,这些映射关系将替换此哈希表拥有的、针对当前指定映射中所有键的所有映射关系。
     * 覆写 Map<K,V> 中的 putAll
     */
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            put(e.getKey(), e.getValue()); // 将e.getKey() 映射到此哈希表中的e.getValue()。
    }
    
    /**
     * 将此哈希表清空,使其不包含任何键。
     * 覆写 Map<K,V> 中的 clear
     */
    public synchronized void clear() {
        Entry<?,?> tab[] = table;
        modCount++;
        for (int index = tab.length; --index >= 0; )
            tab[index] = null;	// 直接置空
        count = 0;
    }
    
    /**
     * 创建此哈希表的浅表副本。复制哈希表自身的所有结构,但不复制它的键和值。这是一个开销相对较大的操作。 
     * 覆写 类 Object 中的 clone
     */
    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) {
            // 这不应该发生,因为我们是Cloneable
            throw new InternalError(e);
        }
    }
    
    /**
     * 返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。
     * 每个条目都按以下方式呈现:键,一个等号 = 和相关元素,其中 toString 方法用于将键和元素转换为字符串。 
     */
    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('{');
        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(", ");
        }
    }
    
    /**
     * 返回此哈希表中的相关类型的枚举。
     * @param type	KEYS or VALUES
     * @return	
     */
    private <T> Enumeration<T> getEnumeration(int type) {
        if (count == 0) { // 如果为0,返回没有元素的枚举。
            return Collections.emptyEnumeration();
        } else {
            return new Enumerator<>(type, false);
        }
    }
    
    /**
     * 返回此哈希表中的相关类型的迭代器。
     * @param type	KEYS or VALUES
     * @return
     */
    private <T> Iterator<T> getIterator(int type) {
        if (count == 0) { // 如果为0,返回一个没有元素的迭代器。
            return Collections.emptyIterator();
        } else {
            return new Enumerator<>(type, true);
        }
    }
    
    // 视图
    
    /**
     * 在第一次请求该视图时,这些字段都初始化为包含适当视图的实例。
     * 视图是无状态的,因此没有理由创建多个视图。
     */
    private transient volatile Set<K> keySet;
    private transient volatile Set<Map.Entry<K,V>> entrySet;
    private transient volatile Collection<V> values;
    
    /**
     * 返回此映射中包含的键的 Set 视图。此 set 受映射支持,因此对映射的更改可在 set 中反映出来,反之亦然。
     * 如果在此 set 上的迭代器处于进行中时修改此映射(除非通过迭代器自身的 remove 操作),
     * 则迭代器的结果是不确定的。通过 Iterator.remove、Set.remove、removeAll、 
     * retainAll、和 clear 操作,此 set 支持元素移除,可从映射中移除相应的映射关系。
     * 它不支持 add 或 addAll 操作。 
     * 覆写 Map<K,V> 中的 keySet
     */
    public Set<K> keySet() {
        if (keySet == null)	// 通过Collections包装,返回的是线程安全的键集
            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();
        }
    }
    
    /**
     * 返回此映射中包含的键的 Set 视图。此 set 受映射支持,因此对映射的更改可在 set 中反映出来,反之亦然。
     * 如果在此 set 上的迭代器处于进行中时修改此映射(除非通过迭代器自身的 remove 操作,
     * 或通过由迭代器返回的映射条目上的 setValue 操作),则迭代器的结果是不确定的。
     * 通过 Iterator.remove、Set.remove、removeAll、 retainAll、 和 clear 操作,
     * 此set 支持元素移除,可从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
     * 覆写  Map<K,V> 中的 entrySet
     */
    public Set<Map.Entry<K,V>> entrySet() {
        if (entrySet==null)	// 通过Collections的包装,返回的是线程安全的键值集
            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);
        }

        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;// 通过hash值找到其存储位置

            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; // 通过hash值找到其存储位置

            @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>)tab[index];
            for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {// 遍历entry链
                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();
        }
    }
    
    /**
     * 返回此映射中包含的键的 Collection 视图。此 collection 受映射支持,
     * 因此对映射的更改可在 collection 中反映出来,反之亦然。
     * 如果在此 collection 上的迭代器处于进行中时修改此映射(除非通过迭代器自身的 remove 操作),
     * 则迭代器的结果是不确定的。通过 Iterator.remove、Collection.remove、removeAll、 
     * retainAll、 和 clear 操作,此set 支持元素移除,可从映射中移除相应的映射关系。
     * 它不支持 add 或 addAll 操作。
     * 覆写 Map<K,V> 中的 values
     */
    public Collection<V> values() {
        if (values==null)// 通过Collections的包装,返回的是线程安全的值集
            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();
        }
    }
    
    // 比较和散列
    
    /**
     * 按照 Map 接口的定义,比较指定 Object 与此 Map 是否相等。
     * 覆写 Map<K,V> 中的 equals
     */
    public synchronized boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> t = (Map<?,?>) o;
        if (t.size() != size())
            return false;

        try {
            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 { // 判断value值
                    if (!value.equals(t.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }
    
    /**
     * 按照 Map 接口的定义,返回此 Map 的哈希码值。 
     * 覆写 Map<K,V> 中的 hashCode
     */
    public synchronized int hashCode() {
        /*
         * 此代码检测由计算自引用哈希表的哈希代码引起的递归,并防止否则会导致堆栈溢出。
         * 这允许带有自引用哈希表的某些1.1时代的applet工作。
         * 这段代码滥用loadFactor字段作为一个hashCode in progress标志执行双重任务,以避免降低空间性能。
         * 负负载因子表示哈希码计算正在进行中。
         */
        int h = 0;
        if (count == 0 || loadFactor < 0)
            return h;  // 返回0

        loadFactor = -loadFactor;  // 标记正在进行的hashCode计算
        Entry<?,?>[] tab = table;
        for (Entry<?,?> entry : tab) {
            while (entry != null) {
                h += entry.hashCode();
                entry = entry.next;
            }
        }

        loadFactor = -loadFactor;  // 标记hashCode计算完成

        return h;
    }
    
    /**
     * 返回指定键映射到的值,如果此映射不包含键的映射,则返回defaultValue。
     * 覆写  Map<K,V> getOrDefault
     */
    @Override
    public synchronized V getOrDefault(Object key, V defaultValue) {
        V result = get(key);
        return (null == result) ? defaultValue : result;
    }
    
    /**
     * 对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。
     * 覆写  Map<K,V> forEach
     */
    @SuppressWarnings("unchecked")
    @Override
    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);     // 如果case表为空,则需要显式检查。
        final int expectedModCount = modCount;

        Entry<?, ?>[] tab = table;
        for (Entry<?, ?> entry : tab) { // 遍历entry链
            while (entry != null) {
                action.accept((K)entry.key, (V)entry.value); // 对给定的参数执行此操作。
                entry = entry.next;

                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }
    
    /**
     * 将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或函数抛出异常。
     * 函数抛出的异常将传递给调用者。
     * 覆写  Map<K,V> replaceAll
     */
    @SuppressWarnings("unchecked")
    @Override
    public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);     //如果case表为空,则需要显式检查。
        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)); // 检查指定的对象(将此函数应用于给定的参数。)引用是否为null。
                entry = entry.next;

                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }
    
    /**
     * 如果指定的键尚未与值关联(或映射到null),则将其与给定值关联并返回null,否则将返回当前值。
     * 覆写  Map<K,V> putIfAbsent
     */
    @Override
    public synchronized V putIfAbsent(K key, V value) {
        Objects.requireNonNull(value);

        // 确保键不在散列表中。
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length; // 通过hash值找到其存储位置
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for (; entry != null; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) { // 若键相同,则新值覆盖旧值
                V old = entry.value;
                if (old == null) {
                    entry.value = value;
                }
                return old;
            }
        }

        addEntry(hash, key, value, index); // 加节点
        return null;
    }
    
    /**
     * 仅当当前映射到指定值时,才删除指定键的项。
     * 覆写  Map<K,V> remove
     */
    @Override
    public synchronized boolean remove(Object key, Object value) {
        Objects.requireNonNull(value);

        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;// 通过hash值找到其存储位置
        @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) && 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;
    }
    
    /**
     * 仅当当前映射到指定值时,才替换指定键的项。
     * 覆写  Map<K,V> replace
     */
    @Override
    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;// 通过hash值找到其存储位置
        @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)) {
                if (e.value.equals(oldValue)) {
                    e.value = newValue;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
    
    /**
     * 如果指定的键尚未与值关联(或映射到null),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非null。
     * 覆写  Map<K,V> computeIfAbsent
     */
    @Override
    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;// 通过hash值找到其存储位置
        @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)) {
                // 哈希表不接受空值
                return e.value;
            }
        }

        V newValue = mappingFunction.apply(key); // 将此函数应用于给定的参数。
        if (newValue != null) {
            addEntry(hash, key, newValue, index); // 加节点
        }

        return newValue;
    }

    /**
     * 指定键的值存在且非空,尝试计算给定键及其当前映射值的新映射。
     * 覆写  Map<K,V> computeIfPresent
     */
    @Override
    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;// 通过hash值找到其存储位置
        @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;
    }

    /**
     * 尝试为指定的键及其当前映射值计算映射(如果没有当前映射,则为null)。
     * 覆写  Map<K,V> compute
     */
    @Override
    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;// 通过hash值找到其存储位置
        @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;
    }

    /**
     * 如果指定的键尚未与值关联或与null关联,则将其与给定的非null值关联。
     * 否则,将关联值替换为给定映射函数的结果,如果结果为null,则删除关联值。
     * 此方法可用于组合键的多个映射值。
     * 覆写  Map<K,V> merge
     */
    @Override
    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;// 通过hash值找到其存储位置
        @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);// 将此函数应用于给定的参数。
                if (newValue == null) {
                    modCount++;
                    if (prev != null) { // 修改指针
                        prev.next = e.next;
                    } else {
                        tab[index] = e.next;
                    }
                    count--;
                } else {
                    e.value = newValue;
                }
                return newValue;
            }
        }

        if (value != null) {
            addEntry(hash, key, value, index); // 加节点
        }

        return value;
    }

    /**
     * 将哈希表的状态保存到流中(即,序列化)。
     */
    private void writeObject(java.io.ObjectOutputStream s)
            throws IOException {
        Entry<Object, Object> entryStack = null;

        synchronized (this) {
            // 写出阈值和负载因子
            s.defaultWriteObject();

            //写出元素的长度和个数
            s.writeInt(table.length);
            s.writeInt(count);

            // 表中条目的堆栈副本
            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;
                }
            }
        }

        //从堆积的条目中写出key/value对象
        while (entryStack != null) {
            s.writeObject(entryStack.key);
            s.writeObject(entryStack.value);
            entryStack = entryStack.next;
        }
    }

    /**
     * 从流中重新构造散列表(即,反序列化)。
     */
    private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException
    {
        // 读取阈值和加载因子
        s.defaultReadObject();

        // 验证loadFactor(忽略阈值——它将被重新计算)
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new StreamCorruptedException("Illegal Load: " + loadFactor);

        // 读取数组的原始长度和元素的数量
        int origlength = s.readInt();
        int elements = s.readInt();

        // 验证#元素
        if (elements < 0)
            throw new StreamCorruptedException("Illegal # of Elements: " + elements);

        // 钳位原始长度要大于元素/加载因子(这是自动增长强制的不变值)
        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);

        // 新长度增加5% + 3,但不大于原来的长度。使长度为奇数,如果足够大,这有助于分配条目。防止长度为零,这是无效的。
        int length = (int)((elements + elements / 20) / loadFactor) + 3;
        if (length > elements && (length & 1) == 0)
            length--;
        length = Math.min(length, origlength);

        if (length < 0) { // overflow
            length = origlength;
        }

        // 检查Map.Entry[].class,因为它是我们实际创建的最近的公共类型。
        SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
        table = new Entry<?,?>[length];
        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
        count = 0;

        // 读取元素的数量,然后读取所有键/值对象
        for (; elements > 0; elements--) {
            @SuppressWarnings("unchecked")
                K key = (K)s.readObject();
            @SuppressWarnings("unchecked")
                V value = (V)s.readObject();
            // 为了提高性能,取消了同步
            reconstitutionPut(table, key, value);
        }
    }

    /**
     * readObject使用的put方法。这是因为put是可覆盖的,并且不应该在readObject中调用,因为子类还没有初始化。
     *
     * 这与常规put方法有几个方面的不同。不需要检查重哈希,因为表中初始元素的数量是已知的。
     * modCount没有增加,也没有同步,因为我们正在创建一个新实例。此外,不需要返回值。
     */
    private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
        throws StreamCorruptedException
    {
        if (value == null) {
            throw new java.io.StreamCorruptedException();
        }
        // 确保键不在散列表中。这在反序列化版本中不应该发生。
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;// 通过hash值找到其存储位置
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                throw new java.io.StreamCorruptedException();
            }
        }
        // 创建新条目。
        @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>)tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }

    /**
     * 哈希表桶冲突列表项
     */
    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;
        }

        /**
         * 直接通过new的方式克隆
         */
        @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();
        }
    }

    // 类型的枚举/迭代
    private static final int KEYS = 0;
    private static final int VALUES = 1;
    private static final int ENTRIES = 2;

    /**
     * 一个散列表枚举器类。该类同时实现枚举和迭代器接口,但是可以在禁用迭代器方法的情况下创建单个实例。
     * 这是必要的,以避免通过传递枚举无意中增加授予用户的功能。
     */
    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
        Entry<?,?>[] table = Hashtable.this.table;
        int index = table.length;
        Entry<?,?> entry;
        Entry<?,?> lastReturned;
        int type;

        /**
         * 指示此枚举数是用作迭代器还是枚举。(true -> Iterator).
         */
        boolean iterator;

        /**
         * 迭代器认为支持散列表应该具有的modCount值。如果违背了这个期望,迭代器将检测到并发修改。
         */
        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;
            /* 使用局部变量加快循环迭代 */
            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;
            /* 使用局部变量加快循环迭代 */
            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;// 通过hash值找到其存储位置

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

猜你喜欢

转载自blog.csdn.net/en_joker/article/details/88868255