HashTable原理和底层实现


上次咱们说到jdk1.8的HashMap原理,这次分析一下HashTable


1.HashMap与HashTable的区别是面试官经常问的一个问题,对于两者的区别有以下几点

  1. HashMap允许null值,而HashTable不允许null值
  2. HashMap是非线程安全的,而HashTable是线程安全的,线程安全会影响读取效率,故HashMap的效率高些
  3. 初始化大小不相同HashMap初始化大小为16,HashTable初始化大小为11,两者的默认加载因子为0.75

2.结构
HashTable与HashMap的结构是一样的,在这不做说明,需要的同学点击下方链接 HashMap
图片取自http://www.imooc.com/article/details/id/23015HashTable最主要的为三个方法 put(),get(),rehash();
put()方法主要逻辑如下

  1. 判断key是否为空,为空丢异常
  2. 如key不为空,则对key进行散列值,也就是调用hashCode方法。
  3. 经过对key的hash运算得出数组下标
  4. 根据下标对获取Entry,如为空,直接添加,如不为空,则代表当前位置已有元素,会进行判断当前key的hash与位置已有元素key的hash值是否相同,如果不相同,走添加方法,如当前key的hash与位置已有元素key的hash相同并且equals也相同,则此时将key与value替代掉此位置原有元素 并返回原有key
  5. put方法为synchronized
public synchronized V put(K key, V value) {
        // Make sure the value is not null
        //判断key是否为null
        if (value == null) {
            throw new NullPointerException();
        }
        // Makes sure the key is not already in the hashtable.
        //将哈希表数据赋值给tab数组
        Entry<?,?> tab[] = table;
        //获取hash值
        int hash = key.hashCode();
        //获取一个小标
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        //根据下标获取元素
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        //元素不为空走循环方法
        for(; entry != null ; entry = entry.next) {
        //判断key是否与原有位置key相同
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
	//不为空或没有进循环中的if则调用添加方法
        addEntry(hash, key, value, index);
        return null;
    }

get()方法逻辑如下

  1. 将哈希表数据赋值给一个变量
  2. 对传入的key进行散列,并获取下标
  3. 拿传入key的hash与数据进行循环比对,如hash相同并且equals也相同则返回value
    代码如下:
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;
    }

rehash()方法逻辑如下

  1. 长度直接扩充到原有两倍加一 ,如果扩充完之后大于长度允许的最大值,则长度变为最大长度
  2. 进行重新计算散列值添加
    代码如下:
protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;
        // overflow-conscious code
        //newCapacity 为扩充完大小
        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;
            }
        }
    }

remove(Object key)逻辑如下

  1. 获取传入key的hash计算出下标
  2. 进行比对如有相同删除
public synchronized V remove(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        //根据key的hash获取下标
        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;
    }

至此HahsTable介绍完毕,面试官问还害怕嘛?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值