HashMap
HashMap综合了数组和链表的优点,是一个查询,插入删除都容易的数据结构。
(1)创建步骤:
①通过hash算法,找到与key对应的存储位置
②访问该位置的value,与当前的value的比较,如果相等就返回,不相等找这个位置对应的链表中的值。
(2)哈希冲突的解决:
①链地址法:key一样的插入元素就链接到那个结点之后。(数组和链表的结合)
②开放地址法:在插入一个元素的时候,先hash()一下,若是发生哈希冲突,就以当前地址为基准,进行再寻址,若发生冲突再去寻找,直至找到一个为空的地址为止。所以这种方法又称为再散列法。
1)顺序寻址:顺序查看当前table,直到找到当前table的下一个空位;
2)二次寻址:以二次幂查看当前table,直到找到当前的下一个空位。
③公共溢出法:一旦由哈希函数得到的地址冲突,就都填入溢出表。所以也就是将其分为哈希表和公共溢出区两个部分。
(4)红黑树:原先当链表中结点大于等于8时,会把链表变成一棵红黑树,小于6时又会转成链表,但是现在通常不这么做了。
(5)hashCode():hashCode实际指的是某一个对象的内存地址返回的一个int型。
(6)rehash() : 之所以要rehash是因为扩容后hash中因为用到了table.length,所以hash出的值一定不一样了,所以要重新hash。
rehash之后可能是:
1)还在那个Index;
2)index+原来table.length
(7)HashTable和HashMap的联系与区别:
1)实现类、实现接口:
HashMap继承自AbstractMap,HashTable继承自Dictionnary;
实现接口都是Map、Cloneable、Serializable。
2) 默认容量:
HashMap:16
HashTable:11
3)构造函数:
HashMap在第一次put的时候初始化table
HashTale构造函数中初始化table
4)put方法:
HashMap | HashTable |
---|---|
是非同步方法 | 是同步方法 |
key/value可为null | key/value不能为null |
2倍方式扩容 | 2倍+1方式扩容(奇数) |
rehash | table中从后往前去遍历,对每一个位置的每一个节点进行rehash,连接到新的位置 |
(该key不存在)尾插 | 头插 |
5)hash算法的差异:
HashMap:
hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
index = hash & table.length-1;
HashTable:
index = (e.hash & 0x7FFFFFFF) % Capacity;
(8)WeakHashMap: 可以增加内存利用率,用的是弱引用,不用的可以回收。