Map集合之HashTable

19 篇文章 1 订阅

HashTable 底层数据结构

HashTableHashMap 一样,都是以键值对的形式存储数据。JDK1.8HashMap 的底层结构是数组 + 链表 + 红黑树,而 HashTable 的底层结构是数组 + 链表

HashTable 源码

HashTable 变量

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
    
    // 键值对 Entry 数组,每个 Entry 本质上是一个单向链表的表头
    private transient Entry<?,?>[] table;

    // 当前表中的Entry数量,如果超过了阈值,就会扩容,即调用rehash方法
    private transient int count;

    // rehash阈值
   private int threshold;

   // 负载因子
   private float loadFactor;

   // 用来实现"fail-fast"机制的(也就是快速失败)。所谓快速失败就是在并发集合中,其进行
   // 迭代操作时,若有其他线程对其进行结构性的修改,这时迭代器会立马感知到,并且立即抛出
   // ConcurrentModificationException异常,而不是等到迭代完成之后才告诉你(你已经出错了)
   private transient int modCount = 0;        
}

HashTable 构造器

// 无参构造器
public Hashtable() {
    this(11, 0.75f);
}

// 明确指定容量的构造器
public Hashtable(int initialCapacity) {
    this(initialCapacity, 0.75f);
}

// 明确指定容量和负载因子的构造器
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);
}

HashTableget() 方法

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

HashTableput() 方法

public synchronized V put(K key, V value) {
        // 值不允许为null
        if (value == null) {
            throw new NullPointerException();
        }

        Entry<?,?> tab[] = table;
        // 得到键的 hash 值
        int hash = key.hashCode();
        // 得到对应 hash 值在数组中的桶索引
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        // 得到桶中链表头节点
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        // 从头开始遍历
        for(; entry != null ; entry = entry.next) {
            // 一旦 hash值 相等并且键相等,替换旧值
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
        // 如果没有找到相同键,那么添加新节点
        addEntry(hash, key, value, index);
        return null;
}

HashTableremove() 方法

public synchronized V remove(Object key) {
        Entry<?,?> tab[] = table;
        // 计算hash值
        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) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
}

jdk 1.5 之前,在并发环境下想要使用 Map 集合,需要使用 HashTable,因为 HashTable 是线程安全的,但是 HashTable 的安全策略过于简单粗暴,是将所有的方法都加上了 synchronized 关键字,在竞争激烈的并发场景中性能就会非常差

jdk 1.5 的时候,增加了并发包 JUC,里面有许多的并发容器,其中就有ConcurrentHashMap,在并发情况下保证了线程安全,同时提供了更高的并发效率

ConcurrentHashMap 详情可以查看:https://blog.csdn.net/weixin_38192427/article/details/112941288

HashTableHashMap 的区别

  • 底层的数据结构:HashTable数组 + 链表,而 HashMap 是数组 + 链表 + 红黑树
  • 默认的初始容量:HashTable11,而 HashMap16
  • 扩容机制:HashTable 扩容后的大小为原来的 2 倍 + 1,而 HashMap 是原来大小的 2
  • 数组的懒加载:Hashtable 在初始化时就创建了数组,HashMap 对底层数组采取的懒加载,即当执行第一次插入时才会创建数组
  • 线程安全:HashTable线程安全的,而 HashMap 是线程不安全的
  • 键和值是否允许为 nullHashTable 不允许,HashMap 中键和值均允许为 null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值