JDK11-HashTable集合

介绍

  •  和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射,底层实现由“数组+链表”实现,相对于hashMap来说简单很多。
  •  Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
  •  Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。
  •  Hashtable中的映射不是有序的
  • 不建议使用,以后说不定哪天就废掉了。连官方文档也说了,如果在非线程安全的情况下使用,建议使用HashMap替换,如果在线程安全的情况下使用,建议使用ConcurrentHashMap替换。

属性

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
    // Hashtable保存数据的数组
    private transient Entry<?,?>[] table;
    // hashtable的容量
    private transient int count;
    // 阈值
    private int threshold;
    // 负载因子
    private float loadFactor;
    // 结构性修改
    private transient int modCount = 0;
}

构造函数

//指定初始容量和加载因子构造函数 
 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);
    }

    /**
      指定初始容量和默认加载因子(0.75)构造函数
     */
   public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

    /**
      默认构造函数,初始容量11,加载因子0.75
     */
    public Hashtable() {
        this(11, 0.75f);
    }

    /**
      给定的map具有相同映射关系的新的hash表
     */
   public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);
    }

添加操作

 

 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;
        int hash = key.hashCode();//获取key的hashCode
        int index = (hash & 0x7FFFFFFF) % tab.length;//确认key的索引位置
        //根据索引找到所处的位置
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        //循环查找,寻找key,并替换
        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;
    }

private void addEntry(int hash, K key, V value, int index) {
        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++;
        modCount++;
    }
//扩容方法
protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // overflow-conscious code
        //扩容大小是原来的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;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }

putAll方法和put方法类似,不再做具体介绍

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

删除操作

//删除置顶key的元素,相对于hashMap简单很多
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)) {
                if (prev != null) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                modCount++;
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }

查找操作

 //很简单,不在介绍
 public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;
    }

总结

  • 首先,Hashtable底层是通过数组加链表实现的,这点和JDK1.8之前的HashMap差不多。
  • 其次,Hashtable是不允许key或者value为null的。
  • 并且,Hashtable的计算索引方法,默认容量大小,扩容方法都与HashMap不太一样。
  • 其实我们可以看到,Hashtable之所以线程安全,大部分方法都是使用了synchronized关键字,虽然JDK优化了synchronized,但在方法上使用该关键字,无疑仍旧是效率低下的操作。就这方面来说,ConcurrentHashMap无疑比Hashtable好多了,后续会有专门文章介绍ConcurrentHashMap,这里就不多说了。

总之呢,Hashtable无疑算是废掉了,说不定过不了多久,它就消失在Map框架中了呢。
 


版权声明:本文为qq_39736103原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。