Map接口,HashMap的底层实现原理
1.map接口的实现类(存储的是双列数据,具有key-value的特点)
HashMap:作为Map的主要实现类,线程不安全,存储null的key与value
LinkedHashMap:遍历元素时,可以按照添加的顺序实现遍历,因为在添加元素的时候,添加了两个引用,前一个元素是什么,后一个元素是什么,适用于频繁的遍历操作
TreeMap:保证按照添加元素的key进行排序,实现排序遍历,考虑key的自然排序与自定义排序
HashTable:作为Map的古老实现类,线程安全,不能存储null的key与value
Properties:常用来处理配置文件,key-value都是String类型
2.Map结构的理解
Map中的key是无序的,不可重复的,使用Set存储所有的key ---》hashMap中key所在的类要重写hashcode和equals方法
Map中的value是无序的,可重复的,使用Collection来存储所有的value
一个键值对构成了一个Entry对象
Map中的Entry是无序的,不可重复的,使用Set存储所有的Entry
3.HashMap与HashTable的异同点
相同点:都是Map接口的实现类
不同点:HashMap是Map接口的主要实现类,线程不安全,效率高,可以存储key-value都为null的数据
HashTable是Map接口的古老实现类,线程安全,效率低,不可以存储key-value都为null的数据
4.HashMap的底层实现原理?以jdk7为例说明
HashMap hashmap = new HashMap();
在实例化以后,底层创建了一个长度为16的一维数组Entry[] table
.....可能执行了很多次put操作....
map.put(key1,value1):
首先调用key1所在类的hashcode()计算key1的哈希值,此哈希值经过某种算法的计算后,得到在数组中的存放位置
如果此位置上的数据为空,key1-value1添加成功 ----------情况1
如果此位置上的数据不为空(意味着此位置上的一个或者多个数据以链表的形式存在),比较key1的哈希值是否与已经存在的一个或者多个数据的key的哈希值是否相同
如果key1的哈希值与已经存在数据的哈希值都不相同,此时key1-value1添加成功----------情况2
如果key1的哈希值与已经存在的某个数据(key2-value2)哈希值相同,继续比较equals()方法
如果equals返回false,则key1-value1添加成功 ----------情况3
如果equals返回true,则将key2替换为key1
注:情况2与情况3,此时的key1-value1和原来的数组以链表方式存储
在不断的添加过程中,会涉及到扩容问题,默认的扩容方式是扩大为原来的2倍,并将原有的数据复制到新的数组中
jdk8较于jdk7底层实现方面有些不同
1.new HashMap()的时候,底层没有创建一个长度为16的数组
2.底层的数组是Node[] 并非原来的Entry[]
3.首次指行put操作的时候,底层才会创建长度为16的Node[]数组
4.jdk7底层是以数组+链表 ,jdk8底层是以数组+链表+红黑树
当数组的某个索引位置上以链表存储数据的个数 > 8个并且数组的长度 > 64的时候,此时会以红黑树的形式存储,方便查找
5.HashMap源码中的一些常量
DEFAULT_INITIAL_CAPACITY: HashMap的默认容量 16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子 0.75
threshold:扩容的临界值 = 默认容量 * 默认加载因子 = 16 * 0.75 = 12