1.Set的底层实现也是Map,但是value值是默认的present。Map用以保存Key-Value的映射关系。
2. Map中的Key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3. Map中的key不允许重复,但value可以重复
tips:当加入相同的key索引至不同的value时,等价于替换value
4. key和value可以为null,但key只能有一个null
5.常用String类作为Map的key
5.1 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的
5.2 HashMap没有实现同步synchronized,因此是线程不安全的
6. k-v的存储
6.1 k-v最后是HashMap$Node node = newNode(hash, key, value, null)
6.2 为了方便遍历,k-v会创建EntrySet集合,该集合存放的元素类型Entry,而一个Entry对象就包含K和V,但存放的不是其本身,而是其地址,本身仍存放在table中的HashMap$Node中
EntrySet集合:EntrySet<Entry<K,V>>
transient Set<Map.Entry<K,V>> entrySet
6.3 entrySet中,定义的类型是Map.Entry,实际上存放的还是HashMap$Node
因为Node是Map.Entry的一个接口实现类
Node类:
static class Node<K,V> implements Map.Entry<K,V>
6.4 当把HashMap$Node对象存放在entrySet里方便遍历,因为Map.Entry类提供了重要方法
K getKey(); V getValue();
7.Map常用方法
map.put(key, value)
map.get(key) //根据key取出值
map.remove() //根据键值删除
map.size() //返回有多少个键值对
map.isEmpty() //
map.clear() //清空整个map
map.containsKey() //查找键是否存在,返回boolean
8. Map的遍历四种法:
8.1 通过keySet遍历得到每一个key ,再通过map.get(key)得到每个值
Map map = new HashMap();
map.put("no1", "dudu");
map.put("no2", "huanhuan");
map.put("no3", "fangbao");
map.put("no4", "fengfeng");
map.put("no5", "taotao");
//遍历方式一;keyset,迭代器
Set keyset = map.keySet();
Iterator iterator = keyset.iterator();
//while循环
while(iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
//增强for
for(Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
8.2 通过entrySet()直接遍历值
//遍历方式三:entrySet获取k-v
Set entrySet = map.entrySet();
//HashMap$EntrySet
//增强for
for (Object entry : entrySet) {
//将entry转为Map.Entry,即EntrySet<Map.Entry<K,V>>
Map.Entry m = (Map.Entry) entry;
//HashMap$Node
System.out.println(m.getKey() + "-" + m.getValue());
}
//迭代器
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object next = iterator3.next();
//运行类型是HashMap$Node
Map.Entry next2 = (Map.Entry) next;
//向下转型
System.out.println(next2.getKey() + "-" + next2.getValue());
}
8.3 values来遍历值
Collection values = map.values();
for (Object value : values) {
System.out.println(value);
}
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {
Object next = iterator2.next();
System.out.println(next);
}
9. HashMap
9.1 HashMap添加key-val流程
通过key的哈希值得到在table的索引
判断该索引处是否有元素,没有元素则直接添加
如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等,直接替换val(此处是和HashSet唯一的不同之处)
如果不相等,需要判断是树结构还是链表结构,做出相应处理。
如果添加时发现容量不够,则需要扩容。
9.2 树化的条件和HashSet相同
树化的反过程:减枝(节点少到一定量之后就变回到链表)
10. 小结:
10.1 HashMap的六种遍历方式
10.2 HashMap扩容机制(Debug源码分析)和红黑树化条件