Hashtable源码分析

Posted moyuduo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hashtable源码分析相关的知识,希望对你有一定的参考价值。

Hashtable源码分析

类结构

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

技术图片

Hashtable继承自Dictionary实现了Map接口。

Hashtable实现了Cloneable可以进行克隆。

Hashtable实现了Serializable可以进行序列化。

属性

//保存节点的数组bucket
private transient Entry<?,?>[] table;

//Hashtable中存放元素的个数
private transient int count;

//Hashtable进行扩容的阈值
private int threshold;

//用于计算阈值的加载因子
private float loadFactor;

//进行破坏结构的修改次数,与遍历时的快速失败有关
private transient int modCount = 0;

//最大容量,2的31次方-9
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

节点

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

构造器

//指定初始化容量和加载因子的构造器
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;
        this.loadFactor = loadFactor;
        table = new Entry<?,?>[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }

//指定初始化大小的构造器
public Hashtable(int initialCapacity) {
  //默认加载因子为0.75
        this(initialCapacity, 0.75f);
    }

//默认初始化大小为11,加载因子为0.75
public Hashtable() {
        this(11, 0.75f);
    }

//使用集合初始化的构造器
public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);
    }

方法

Hashtable的所有方法都加了synchronized关键字,所以是线程安全的

contains(Object)方法判断Hashtable中是否包含某个元素

public synchronized boolean contains(Object value) {
        if (value == 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)) {//使用保存节点的V的equals方法判断是否相等
                    return true;
                }
            }
        }
        return false;
    }

containsKey(Object)判断Hashtable中是否包含这个key

public synchronized boolean containsKey(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
  //计算下标的公式,如果包含这个key那么一定在数组的这个位置上或后继节点上
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {//hash值要相等并且key要equals
                return true;
            }
        }
        return false;
    }

get(Object)方法根据key获取值,不能使用null的key,会抛出NullPointerException

public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
  //key为null会抛出NullPointerException
        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)) {
                return (V)e.value;
            }
        }
        return null;
    }

put(K,V)向Hashtable中添加元素,可以看到Hashtable不允许key或value为null,抛出NullPointerException

public synchronized V put(K key, V value) {
        // 确保添加的value不空
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
  //key为null会抛出NullPointerException
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];//通过key计算下标,如果该key已经使用,那么一定在该节点或该节点的后继
        for(; entry != null ; entry = entry.next) {//遍历
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
//如果没找到key对应的节点,说明key没有使用过,那么新增节点保存<K,V>
        addEntry(hash, key, value, index);
        return null;
    }

private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
        if (count >= threshold) {//达到了阈值要进行扩容
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = key.hashCode();
            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++;
    }

protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // 新容量为老容量的2倍+1
        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<?,?>[] 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;
              //头插法
              //把新计算下标的元素挂到当前元素的next
                e.next = (Entry<K,V>)newMap[index];
              //把当前元素添加到新下标位置
                newMap[index] = e;
            }
        }
    }

remove(Object)方法根据key移除Hashtable中的节点

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) {
            if ((e.hash == hash) && e.key.equals(key)) {//找到要移除的节点
                modCount++;
                if (prev != null) {//如果有前驱把前驱的next指向移除节点的next
                    prev.next = e.next;
                } else {//没有前驱说明是保存在table数组中的元素,直接把该元素的后继保存到数组
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }

remove(Object,Object)根据key和value移除节点,也需要key和value都不为null

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) {
            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {//通过key和value一起判断
                modCount++;
                if (prev != null) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                e.value = null;
                return true;
            }
        }
        return false;
    }

replace(K,V,V)根据K,V把找到节点把原value替换为新value

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) {
            if ((e.hash == hash) && e.key.equals(key)) {//根据key找到节点
                if (e.value.equals(oldValue)) {//判断原value是不是和参数一致
                  //替换
                    e.value = newValue;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

replace(K,V)根据key找到节点使用新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) {
            if ((e.hash == hash) && e.key.equals(key)) {//使用key判断
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
        return null;
    }

以上是关于Hashtable源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Hashtable源码分析

Hashtable源码分析

HashTable源码分析

Java源码分析HashTable源码分析

Java源码分析HashTable源码分析

Hashtable源码分析