特点:
1.无序,键值对,键不能重复,值可以重复,这里的无序指的也是插入的顺序和读取的顺序是不一样的,和set集合一样。
- 键重复则覆盖,没有继承Collection接口,它单独继承Map接口,和list,set不一样,这两个继承collection接口
扩容:
初始容量16,负载因子0.75,扩容增量1倍
遍历:
先获取所有键的Set集合,再遍历(通过键获取值)取出保存所有Entry的Set,再遍历此Set即可。
map的实现类
HashMap
线程不安全,最常用,速度快
内部采用数组来存放数据
put的执行过程
流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。
Table数组中的的Node
jdk1.8之前的链表结构示意图
jdk1.8 后的红黑树示意图
在这里,不得不说一下,什么是红黑树
特性:
- 每个节点要么红要么黑
- 根节点是黑色
3 .每个叶子节点都是黑色(叶子是NULL节点表示 或 NIL节点表示)。 - 如果一个节点是红色的,那么它的子节点必须是黑色的子节点。(即不存在两个连续的红色节点)
- 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。
红黑树其实就是以第一个数据作为判断依据,后面进来的数据与其做比较,比他小的就在这个数的左边,比这个数大的就在右边,然后继续往下走,接在下面一步一步往下走,这就是红黑树。
这里提供一个可视化红黑树网址
点我跳转红黑树https://www.cs.usfca.edu/~galles/visualization/RedBlack.html说完红黑树,我们来说一下jdk1.8之前的hashmap的原理怎么样的
首先在hashmap的底层有一个叫桶的数组,默认长度为16,这数组并不是保存的我们进来的元素,而是保存一个指向数据节点的一个指针,引用,首先通过key值hash运算,得到hashcould值,然后确定在数组上的位置,然后数据进来一个一个往下面的链表挤,往下挤,无论你有多少的元素我都一直往下挤。
而在jdk1.8后,先进行一个判断,判断你的元素长度是否大于8,如果小于8是一个链表结构,如果大于8是一个红黑树的结构,红黑树结构上面已经说了,所以这就是jdk1.8之后的一个区别,这样的结构使得map的速度更快了。
HashTable
线程安全,不太常用,与vector类似,将所有数据加一把锁,性能很高
ConcurrentHashMap
线程安全,比HashTable性能高,jdk1.8之前采用16把分段锁,将数据加锁,jdk1.8之后是每一个在数组的桶加锁,每一个桶一把锁,有多少桶就加多少锁,中间在赋值的时候才用的是cas,比较并替换。
TreeMap
key值按一定的顺序排序,添加或获取元素时性能较HashMap慢,因为需求维护内部的红黑树,用于保证key值的顺序
LinkedHashMap
继承HashMap
LinkedHashMap是有序的,且默认为插入顺序
当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了
代码实现
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("name1", "josan1");
linkedHashMap.put("name2", "josan2");
linkedHashMap.put("name3", "josan3");
Set<Entry<String, String>> set = linkedHashMap.entrySet();
Iterator<Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
案例代码,上面的具体代码
package com.zking.test;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.Before;
import org.junit.Test;
public class Maptest {
private Map<String, String> map = new HashMap<>();
@Before
public void setup() {
map.put("1", "李凝");
map.put("2", "张山");
map.put("3", "吴飞");
map.put("4", "徐民");
}
@Test
public void demo1() {
System.out.println(map.get("3"));
}
@Test
public void demo() {
map.put("5", "zs");
System.out.println(map.get("1"));
System.out.println(map.get("5"));
}
@Test
public void demo2() {
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println(map.get(key));
}
// 获取value值
}
@Test
public void demo9() {
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Entry<String, String> entry = it.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 获取key+value值
}
@Test
public void demo10() {
map.forEach((key, val) -> System.out.println(key + ":" + val));
// foreach遍历出key+value值
}
@Test
public void demo11() {
if (!map.containsKey("4")) {
map.put("4", "徐民");
}
map.putIfAbsent("4", "白牙");
// map.putIfAbsent()如果这元素存在就不覆盖,put如果存在就覆盖
// 使用 put 方法添加键值对,如果 map 集合中没有该 key 对应的值,则直接添加,
// 并返回 value;如果已经存在对应的值,则会覆盖旧值,value 为新的值,返回值为 value。
//
// 2.使用 putIfAbsent 方法添加键值对,如果 map 集合中没有该 key 对应的值,则直接添加,
// 并返回 null,如果已经存在对应的值,则依旧为原来的值,返回值为 value(旧的值)。
map.forEach((key, val) -> System.out.println(key + ":" + val));
}
@Test
public void demo3() {
Map<String, String> map = new HashMap<>();
map.put("1", "李凝");
map.put("2", "张山");
map.put("3", "吴飞");
map.put("4", "徐民");
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Entry<String, String> next = it.next();
System.out.println(next.getKey() + " : " + next.getValue());
}
// 迭代器遍历出元素
}
@Test
public void demo4() {
// 对已存在的key为1的记录进行了覆盖
map.put("1", "微信");
System.out.println(map.get("1"));
}
@Test
public void demo5() {
// 如果指定的key值不存在,则加入map
if (!map.containsKey("2")) {
map.put("2", "rest");
}
// 更简单的方式
String val = map.putIfAbsent("2", "rest");
System.out.println(map.get("2"));
System.out.println(val);
}
@Test
public void demo6() {
map.remove("1");
map.forEach((key, val) -> System.out.println(key + ":" + val));
//删除方法
}
@Test
public void demo12() {
Hashtable<String, String> table = new Hashtable();
table.put("1", "指针");
table.forEach((key, val) -> System.out.println(key + ": " + val));
// Hashtable
}
@Test
public void demo13() {
ConcurrentHashMap<String, String> table = new ConcurrentHashMap<>();
table.put("1", "指针");
table.forEach((key, val) -> System.out.println(key + ": " + val));
}
// ConcurrentHashMap
}
private TreeMap<String,Student> treeMap;
@Before
public void setup() {
treeMap = new TreeMap<String,Student>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
// 负数 0 正数
return o1.compareTo(o2);
}
});
treeMap.put("1", new Student(1, "zs", 0));
treeMap.put("2", new Student(3, "ls", 0));
treeMap.put("3", new Student(2, "ww", 0));
treeMap.put("4", new Student(4, "zl", 0));
}
@Test
public void demo1() {
treeMap.forEach((key, val) -> System.out.println(key + ":" + val));
}
版权归原作者 赤诚& 所有, 如有侵权,请联系我们删除。