HashMap Hashtable
空:key,value都可空 key可空,value为空抛出异常,
重:key重复会覆盖之前的value, key重复会覆盖之前的value,
序:无序, 无序(有序和无序的源头是HashMap和Hashtable是通过什么方式存储数据的,Entry<K,V>链表以 及table数组,怎么是实现的看源码)
安:线程不安全 线程安全(基本每个方法前加关键字synchronized)-(能说出synchronized和lock()的区别么?)
1.HashMap的初始化
在jdk1.7中,HashMap的默认初始化中,分配的数组大小为16。
default_initial_capacity= 16;
maximum_capacity =1<<30; (2^30 =1073741824)
default_loader_factor= 0.75f;
底层是链表的数组,key的引用地址放在数组中,数据放在链表里,数组放链表的头,
比如int[] its = new int[16];
按照hash(key)%16 = x,则Entry<key,value>就放在x中的一个位置,;
为什么要用数组和链表的结合呢? 因为数组适合数据的查找,在增删数据的时候需要移动组内元素,所以速度较慢,而链表在查找数据的时候较慢,而增删数据只需要移动指针就可以,所以两者的结合使得HashMap有较快的查数据和增删数据能力。
下面我们来认识HashMap的底层实现,数组加链表是HashMap的底层实现,通过一个Table来管理每个链表的头,每个链表的头怎么选择key呢?看下面的源码。
public V put(Kkey,V value){
...
int hash =hash(key);
int i =indexFor(hash, table.length);
...}
key在被put时,先hash()方法,该方法对key做位计算,求出哈希值,再通过indexFor()求出在数组中,这个key放在哪个位置处,通过hash%table.length取余,比如:
Map<String,int>map = new HashMap(16);
m.put(key1,"1")';
m.put(key2,"2");
m.put(key3,"3");
m.put(key4,"4");
我创建了一个数组大小为16的HashMap,四个key的hash值算出来分别是16,17,32,18;那么执行hash%table.length之后,分别是0,1,0,2,所以放的位置分别是table[0],table[1],table[0],table[2]。
所以四个值是这么放的。
每次put先回去判断是否key为空,如果空,那么执行putForNullKey(),再判断是否已经有同一个key存在,如果存在则将原来的value返回,并将新的value保存到对应的key处,
一个table数组
Entry<k,v>链表 每一个椭圆代表的是一个Entry<k,v>对象,而一个方块就是Entry<k,v>[0]因为链表的内容就是Entry<k,v>,通过一个HashMap$Entry对象的next变量来串联起多个Entry形成一个链表。
public V put(K key, V value) {
if (table ==EMPTY_TABLE) inflateTable(threshold); -------------1-------
if (key== null) return putForNullKey(value);----------------------2-------
int hash= hash(key);
int i =indexFor(hash, table.length);-------return hash & (table.length-1)--------
for(Entry<K,V> e = table[i]; e != null; e = e.next) {---------------3-------
Objectk;
if(e.hash == hash && ((k = e.key) == key || key.equals(k))) {-4-----
VoldValue = e.value;
e.value= value;
e.recordAccess(this);
returnoldValue;----------------------------------------------5-------
} }
modCount++;------------------------------------------------------6------
addEntry(hash,key, value, i);---------------------------------------7-----
return null;
}