HashMap和HashTable的区别

一、HashMap简介

1.HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,超过阀值时,会自动增长。HashMap常量源码:

//默认容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//链表 转成 红黑树 的阈值
static final int TREEIFY_THRESHOLD = 8;
//红黑树 转为 链表 的阈值
static final int UNTREEIFY_THRESHOLD = 6;
//存储方式由链表转成红黑树的容量的最小阈值
static final int MIN_TREEIFY_CAPACITY = 64;
//HashMap中存储的键值对的数量
transient int size;
//扩容阈值,当size>=threshold时,就会扩容
int threshold;
//HashMap的加载因子
final float loadFactor;

<<运算符,表示移位操作。每次向左移动一位(相对于二进制来说),表示乘以2,此处1<<4表示00001中的1向左移动了4位,变成了10000,换算成十进制就是2^4=16,也就是HashMap的默认容量就是16。加载因子(load_factor)默认为0.75,当HashMap中存储的元素的数量大于(容量×加载因子),也就是默认大于16*0.75=12时,HashMap会进行扩容的操作。
2.HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。

3.HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。

4.HashMap存数据的过程:
HashMap内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表。当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,然后通过indexFor(hash,length)求该key-value对的存储位置,计算方法是先用hash&0x7FFFFFFF后,再对length取模,这就保证每一个key-value对都能存入HashMap中,当计算出的位置相同时,由于存入位置是一个链表,则把这个key-value对插入链表头。
5.HashMap中key和value都允许为null。key为null的键值对永远都放在以table[0]为头结点的链表中。当key=null时,则hash值为0。

//如果原来存在相同的key-value,原来的value会被替换掉
public V put(K key, V value) {
  return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
  int h;
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

二、Hashtable简介
1.Hashtable是基于哈希表实现的,每个元素是一个key-value对,其内部是通过单链表解决冲突问题,容量不足时,会自动增长。

2.Hashtable是JDK1.0引入的类,线程安全的,可用于多线程环境。

3.Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
HashMap和HashTable的区别_第1张图片
HashMap重新计算Hash值源码:

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

你可能感兴趣的:(后端)