目录
-----第一章
----------为什么要深入学习HashMap?
----------HashMap与HashTable的区别是什么?
----------自定义HashMap中的Entry<K,V>对象
----------使用ArrayList集合实现简易版HashMap
----------使用LinkedList链表实现简易版HashMap
----------HashCode和equals的区别
----------如何解决HashCode碰撞问题
----------纯手写HashMap中的put方法
----------纯手写HashMap中的get方法
-----第二章
----------HashSet基本API使用介绍
----------HashSet底层原理分析
----------HashMap底层基本实现原理分析
----------HashMap构造函数实现原理分析
----------HashMap第一次数组扩容原理
----------HashMapPut方法源码分析
-----第三章
----------HashMapJDK1.7面试题总结
----------HashMapJDK1.7扩容死循环原理分析
----------HashMapJDK1.8什么要使用红黑树
----------数据结构中时间复杂度对比
----------二叉搜索树基本实现原理与思想
----------手写二叉搜索树添加功能
----------手写二叉搜索树查询功能
----------总结二叉搜索查询存在哪些问题
-----第四章
----------二叉搜索树存在那些问题
----------红黑树的数据结构基本介绍
----------红黑树基本的特征介绍
----------红黑树变换颜色的规则要求
----------红黑树左右旋转基本的规则
----------手写红黑树环境代码实现
----------手写红黑树实现二叉树
----------红黑树规则破坏如何实现修复
-----第五章
----------手写红黑树左旋转代码演示
----------红黑树基本变色旋转规则回顾
----------纯手写一步一步写左旋转
----------红黑树基本左旋变颜色01
----------红黑树基本左旋变颜色02
----------红黑树基本左旋变颜色03
----------红黑树基本左旋变颜色04
----------红黑树查询左大值与最小值
-----第六章
----------HashMap8基本实现原理分析
----------HashMap8优化了7那些bug
----------HashMap8的Put方法实现原理01
----------HashMap8的Put方法实现原理02
----------HashMap8的Put方法扩容实现
----------HashMap8的Put方法源码分析总结
HashMap与HashTable的区别是什么?
当面试官问到HashMap的时候,一定会问到HashMap与HashTable之间区别是什么,这个问题是HashMap最经典的面试题之一,在后面会总结一下HashMap所有的面试题,让读者在遇到HashMap面试时游刃有余。
基于JDK1.7的HashMap的put方法源码:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
基于JDK1.7的HashMap的get方法源码:
public V get (Object key){
if (key == null)//如果Key值为空,则获取对应的值,这里也可以看到,HashMap允许null的key,其内部针对null的key有特殊的逻辑
return getForNullKey();
Entry<K, V> entry = getEntry(key);//获取实体
return null == entry ? null : entry.getValue();//判断是否为空,不为空,则获取对应的值
}
基于JDK1.7的HashTable的put方法源码:
public synchronized V put (K key, V value){
if (value == null) {
throw new NullPointerException();
}
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K, V> e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
Entry<K, V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}
基于JDK1.7的HashTable的get方法源码:
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K, V> e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
对比HashMap和HashTable的get和put方法,可以发现这两者最大的区别就是有没有在方法上加上线程锁synchronized ,所以这两者最大的区别就是线程的安全问题,这也是为什么HashMap效率快的原因之一,它舍弃了安全问题,来提高了自身的效率。
HashMap和HashTable还有哪些区别吗?
当然是有的,只是比较常问的就是线程安全问题了
HashMap | HashTable | |
---|---|---|
线程安全 | 不安全,多线程时存在bug | 安全,使用synchronized 关键字 |
Key能否为null | 能,固定存放在数组的 | 不能,会报NullPointerException异常 |
初始容量 | 16 | 11 |
Hash值 | 重新计算Hash值(1.7和1.8不一样) | 使用key原本的Hash值 |
扩容方式 | 2的幂次方 | 2的幂次方+1 |
遍历方式 | Iterator | Iterator+历史原因保留Enumeration |
是否提供contains方法 | containsValue和containsKey | contains,containsValue和containsKey |
父类 | AbstractMap | Dictionary |
HashMap和HashTable的相同点有哪些
- 底层数据结构相同,都为数组+链表
- key都不能重复
- 都是无序集合
- 都是通过key进行哈希运算
- 都实现了Map接口