一、几个实现类的比较
1.HashMap:最常用的,线程不安全,效率高;可以存储null值的key或者value
LinkedHashMap是其子类,频繁的便利操作执行效率高于HashMap
底层实现:
jadk7以及之前:数组+链表
jdk8:数组+链表+红黑树
2.TreeMap:
按照key进行排序,底层是红黑树
3.Hashtable:古老实现类;线程安全的所以效率低,而且不能存储null值的key或value
properties是其子类,用来处理配置文件,key和value都是string类型
1.0先是有Hashtable,1.2的时候出现Map及其实现类HashMap和TreeMap,1.4加了个LinkedHashMap
二、关于Map的键值对
当我们使用map的put方法put(key,value)时,java会把key、value封装成一个entry然后存到map里面,其中key是不可重复的,value随便。
key放在set中:无序不可重复,所以这里的元素要equals和hashCode
value放在collection中:无序但可重复
entry放在set里面:无序不可重复(按key算)
三、HashMap源码解析
jdk7:
HashMap map = new HashMap()的时候,在底层创建长度为16的数组Entry[] table
执行put的时候,也是先hashCode算出hash值,然后在计算出在数组里的位置(一般用&length-1来算,因为length是先在数组的长度,&length-1的话最大值就是length-1就不会超出这个坐标),然后看看有没有东西,有的话和链表里的先比较hash值然后equals函数,如果都一样,这时候新的value会替换旧的value
扩容:当数据个数超出存放值且此时要存的位置非空的时候(要形成链表)扩容,扩容为原来的两倍,并且所有数据全部从新计算hash值并且分布。
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树
UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
table:存储元素的数组,总是2的n次幂
entrySet:存储具体元素的集
size:HashMap中存储的键值对的数量
modCount:HashMap扩容和结构改变的次数。
threshold:扩容的临界值,=容量*填充因子
loadFactor:填充因子
jdk8:
一开始底层不创建数组,首次put的时候创建,数组为Node[] table,当某个链表数据个数>8且,数组的length>64的时候,链表上的数据会改成使用红黑树存储。(因为当length>64的时候表明数组已经足够长了,否则可能会先扩容分散列表而不是弄成红黑树)
注:set中的add方法就是调用了map的put,元素放进key里面,value里放一个static object,所有value公用一个object(防止空指针异常,但是calue本身没用),因此set就是用hashmap做的。