HashMap的数据结构
数组的特点是:查询快,插入和删除慢;
根据下标可以直接访问到数组对应下标元素;插入和删除的时候,需要对元素进行移位
链表的特点是:插入和删除快,查询慢
插入和删除只需要找到位置,修改对象的pre,next引用即可,而查询需要从第一个元素遍历找下去
说完数组和链表,接下来讲一下HashMap
HashMap是基于数组和链表实现<key,value>键值对的数据结构,默认初始容量是16,负载因子0.75,扩容大小为原来的2倍
特点:
- 允许空键和空值,键是不可重复的(但空键只有一个,且放在第一位)
- 元素是无序的,且顺序会不定时改变
- 底层是链表数组,jdk8后又加了红黑树
- key是存在Set集合中,需要对key重写equals方法和hashCode方法
- 非线程安全
我们使用put(key,value)方法往HashMap中添加数据,使用get(key)获取对应的value
put(key,value)会调用key的hashcode值对map长度取余计算bucket(数组里可以存储元素的位置被称为“桶(bucket)”)位置,用于存储Node(JDK7里面用的Entry存储,JDK8里面用的Node;都是链表结构,包含了hash,key,value,next的引用);如果在put的时候出现hash碰撞时,对象将会存储在链表的下一个节点。
get(key) 会通过key的hashcode取余之后找到bucket位置,返回Node对象;当get(key)方法两个key的hashcode取余相同的时候,在找到bucket位置之后,会调用key.equals()方法找到正确的节点,返回Node对象
如果hashMap的大小超过了负载因子:hashMap的默认负载因子是0.75,当一个map的容量达到75%的时候,将会创建原来hashMap大小的两倍的数组,重新调整hashmap的大小,并且将原来的对象调用hashcode找到新的bucket位置。这个过程叫做:rehashing
遍历map的四种方式
1、使用for-each迭代entry
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(Map.Entry<Integer, Integer> entry : map.entrySet()){
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue())
}
2、使用for-each迭代keys,values
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//iterating over keys only
for (Integer key : map.keySet()) {
System.out.println("Key = " + key);
}
//iterating over values only
for (Integer value : map.values()) {
System.out.println("Value = " + value);
}
3、使用Iterator迭代
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
4、迭代keys并搜索values(耗时,低效,不推荐)
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key = " + key + ", Value = " + value);
}
一般业务来说,需要使用map的key和value用第一种方式就好,需要删除map中的元素是使用第三种Iterator方式
在jdk8中,HashMap新增红黑树存储;
map中新增数据导致链表长度等于8的时候,链表会转化为红黑树存储;map中移除数据使红黑树的节点等于6的时候会转化为链表存储
红黑树本质上是一种二叉查找树,但它在二叉查找树的基础上额外添加了一个标记(颜色),同时具有一定的规则。
*每个节点要么是红色,要么是黑色;
*根节点永远是黑色的;
*所有的叶节点都是是黑色的
*每个红色节点的两个子节点一定都是黑色;
*从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点
最后,有不严谨或者错误的,请指正