zoukankan      html  css  js  c++  java
  • 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;
        }
    
  • 相关阅读:
    Java中的枚举与values()方法
    为什么要使用双亲委派机制?
    java中finalize()方法
    jdk中rt.jar的作用
    IDEA查看maven依赖树,找出冲突jar包,以及 exclusion 冲突的包
    Linux 环境下SQLPLUS 回退键无法使用处理方法
    Hive字段注释会显示成from deserializer
    LinkedList类的poll、pop等方法
    static代码块执行顺序
    机器学习--线性回归
  • 原文地址:https://www.cnblogs.com/moyuduo/p/12742303.html
Copyright © 2011-2022 走看看