Map:双列数据,存储key-value对的数据
HashMap:作为Map的主要实现类;线程不安全,效率高,可以存储null的key和value。底层:数组+链表(jdk7及之前);数组+链表+红黑树(jdk8)
LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历,原因:在原有的HashMap底层结构基础上,添加了一对指针,只想前一个和后一个元素。对于频繁的遍历操作,执行效率高于HashMap。
TreeMap:保证按照添加的key-value对进行排序,实现排序遍历,此时考虑key的自然排序或定制排序。底层使用红黑树
Hashtable:作为古老的实现类,线程是安全的,效率低,不能存储null的key和value
Properties:常用来处理配置文件,key和value都是String类型
2.Map结构的理解
Map中的key:无序的、不可重复的,使用Set存储所有的key -> key所在的类要重写equals()和HashCode()方法(以HashMap为例)
Map中的value:无序的、可重复的、使用Collection存储所有的value -> value所在的类要重写equals()
一个键值对:key-value构成了一个Entry对象
Map中的Entry:无序的、不可重复的,使用Set存储所有的Entry
3.HashMap的底层实现原理(jdk7)
1.HashMap map = new HashMap();
在实例化以后,底层创建了长度是16的一维数组,类型为Entry[]名字为table。
2.map.put(key1,value1);
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算之后,得到在Entry数组中的存放位置。
如果此位置上数据为空,此时添加成功。-------情况1
如果此位置上的数据不为空(意味着此位置上存在一个或多个数据<以链表形式存在>),比较key1和已经存在的一个或多个数据的哈希值:
如果都不相同,此时添加成功。--------情况2
如果和某一个已经存在的数据(key2,value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:
如果返回false:添加成功。 --------情况3
如果返回true:使用value1替换value2。
补充:关于情况2和情况3,此时key1-value1和原来的数据以链表的形式存储。
3.在不断的添加过程中,会涉及到扩容问题,当超出临界值且存放的位置非空时进行扩容,默认的扩容方式,扩容为原来的2倍,并将原有的数据复制过来。
jdk8相较jdk7的不同:
1.new HashMap():底层没有创建一个长度为16的数组,首次调用put()时才创建
2.jdk8底层的数组是Node[]而不是Entry[]
3.jdk8中的底层结构:数组+链表+红黑树
当数组的某一个索引位置上的的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时索引位置上的所有数据改为用红黑树存储,提高比较时的效率