【视频网址】:慕课网——Map从入门到性能分析
简介:Map是开发中,使用频率最高的知识点之一,Map家族也有很多成员,例如HashMap,LinkedMap等, 怎样更好地使用Map家族的这些成员,速度效率怎么更好地得以发挥,我将自己的一些经验与大家分享。
工程文件【链接:https://pan.baidu.com/s/1Vg3FLVtGeCCKZ3R68Xi2tA【提取码:zjxs】
目 录
第3章 HashMap的原理
3-1 HashMap例题2(15:58)
将Map中的value以对象的形式进行存储。
对象包含对象!
对于 小Map:key是三门课程,value是成绩(90、80、72)。
对于 大Map:key是zhang1,value是map1、map2、map3...
//加上泛型,只能存Map;不加泛型,存啥都行。一般都加泛型 //List list = new ArrayList(); //List<Map> list = new ArrayList<Map>(); List<Map<String, String>> list = new ArrayList<Map<String, String>>();
使用Map进行定位,更方便。
package com.imooc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestMap1 {
public static void main(String[] args) {
Map<String, Map> stuMap = new HashMap<String, Map>();//<String, Object> Map也是Object
Map<String, String> stu1Map = new HashMap<String, String>();
stu1Map.put("1yuwen", "11");
stu1Map.put("2shuxue", "12");
stu1Map.put("3yingyu", "13");
Map<String, String> stu2Map = new HashMap<String, String>();
stu2Map.put("1yuwen", "21");
stu2Map.put("2shuxue", "22");
stu2Map.put("3yingyu", "23");
Map<String, String> stu3Map = new HashMap<String, String>();
stu3Map.put("1yuwen", "31");
stu3Map.put("2shuxue", "32");
stu3Map.put("3yingyu", "33");
Map<String, String> stu4Map = new HashMap<String, String>();
stu4Map.put("1yuwen", "41");
stu4Map.put("2shuxue", "42");
stu4Map.put("3yingyu", "43");
Map<String, String> stu5Map = new HashMap<String, String>();
stu5Map.put("1yuwen", "51");
stu5Map.put("2shuxue", "52");
stu5Map.put("3yingyu", "53");
stuMap.put("zhang1", stu1Map);
stuMap.put("zhang2", stu2Map);
stuMap.put("zhang3", stu3Map);
stuMap.put("zhang4", stu4Map);
stuMap.put("zhang5", stu5Map);
System.out.println(stuMap);
System.out.println(stuMap.get("zhang3"));
//加上泛型,只能存Map;不加泛型,存啥都行。一般都加泛型
//List list = new ArrayList();
//List<Map> list = new ArrayList<Map>();
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
list.add(stu1Map);
list.add(stu2Map);
list.add(stu3Map);
list.add(stu4Map);
list.add(stu5Map);
System.out.println(list);
System.out.println(list.get(2));
}
}
3-2 HashMap底层原理1(08.50)
HashMap初始化大小,默认是长度为16的数组。
底层原理:取余数实现定位!底层代码:通过位运算取余数进行定位。
链表形式存储。entry中的next变量解决碰撞问题!【8的坐标指向120,120的键值映射中的next指向40,40的next指向null。】
取值:key转换成哈希码!!!
package com.imooc;
import java.util.HashMap;
import java.util.Map;
public class TestMap2 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
//map.put(120,"a");//120是int类型的,自动转成Integer
map.put(new Integer(120), "a");
map.put(new Integer(37), "a");
map.put(new Integer(61), "a");
map.put(new Integer(40), "a");
map.put(new Integer(92), "a");
map.put(new Integer(78), "a");
System.out.println(map);
}
}
3-3 HashMap底层原理2(06.14)
- 根据key得到优化后的哈希码;
- 根据优化后的哈希码,对长度取余,得到的余数就是位置。【底层通过位运算求余!】
有效使用空间:默认长度*负载因子。超出之后,进行扩容,默认扩容1倍。
Java开源团队多次实验的结果:16、0.75最佳!!!
3-4 HashMap构造方法优化1(13:56)
初始化大小。创建好的HashMap长度为3。
HashMap构造方法的优化:将传递的参数转化为“大于参数的最小的2^n”。【2^2-->4】负载因子:占有率达到多少后,进行扩容,扩容1倍。
负载因子为1:0~15的位置,都要占满,才会扩容。数字求余,决定所处位置。
可能会在某个位置出现多次碰撞,始终达不到100%的占用,导致节点中产生空度映射关系。
链表达到一定量后,将其转换为 红黑树!!!
调整位置:运行时间、性能消耗。扩容次数,越少越好!-->考虑初始化大小!-->与业务匹配!
3-5 HashMap构造方法优化2(12:02)
第1次 运行时间较长,程序第1次执行的时候要进行内存的分配。【Java虚拟机做内存分配!】
package com.imooc;
import java.util.HashMap;
import java.util.Map;
/**
* 1、创建10个HashMap,每个HashMap含有10万条记录;
* 2、传递不同的构造方法的参数,比较速度;
* 3、实验参数:构造方法传参(16, 0.75f)和(16384, 0.75).
*/
public class TestMap3 {
public static void main(String[] args) {
Long sum = 0L;
for (int i = 0; i < 10; i++) {
sum += new TestMap3().inputMap1(10000, 0.75f);
}
System.out.println(sum / 10);
}
private Long inputMap1(int initialCapacity, float loadFactor) {
String key, value;
Map<String, String> map1 = new HashMap<String, String>(initialCapacity, loadFactor);
Long start = System.nanoTime();//计算时间、Long型变量 计数器---纳秒
for (int i = 0; i < 10000; i++) {
key = String.valueOf(i);
value = "value";
map1.put(key, value);
}
Long end = System.nanoTime();
Long time = end - start;
System.out.println("time:" + time);
return time;
}
}
3-6 HashMap常用方法1(20:50)
package com.imooc;
import java.util.HashMap;
import java.util.Map;
/**
* 用的到技术点:
* 1、putIfAbsent、put
* 2、replace
* 3、remove、cLear
* 4、containsKey、containsValue
* 5、isEmpty
*/
public class TestMap4 {
public static void main(String[] args) {
Map<String, String> map1 = new HashMap<String, String>();
map1.put("a", "111");
map1.put("b", "222");
map1.put("c", "333");
map1.put("d", "444");
map1.put("e", "555");
//1、判断是否为空
boolean isNull = map1.isEmpty();
System.out.println("map1 is Null: " + isNull);
//2、删除节点
// map1.remove("a1");
// map1.remove("a","123");
//3、清空HashMap对象
// map1.clear();
//4、判断是否有某个key
boolean isFlag = map1.containsKey("a");
System.out.println(isFlag);
//5、判断是否有某个value
boolean isFlag2 = map1.containsValue("555");
//6、HashMap替换某个key的value
map1.replace("a", "111111111");//key存在,就更新
map1.replace("b", "2202", "22222");//key、value匹配,才更新
map1.put("c", "33333");//key存在,则替换value;key不存在,则新增key
System.out.println(map1);
//7、putIfAbsent
//避免代码量多,遗忘map中已存在的键值对,而进行替换
if (map1.containsKey("c") && map1.containsValue("333")) {
map1.put("c", "33333");
}
//避免代码量多,遗忘map中已存在的键值对,而进行替换【有效避免!!!】
String x = map1.putIfAbsent("x", "8");//x存在,不执行put,输出x对应的值;x不存在,则put,输出null
System.out.println(x);
}
}
3-7 HashMap常用方法2(07:21)
package com.imooc;
import java.util.HashMap;
import java.util.Map;
/**
* 1、map.forEach((key, value) -> System.out.println(key + ":" + value));
* Lamaba表达式:->
* 2、getOrDefault(key, defaultValue)
*/
public class TestMap5 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(new Integer(11), "a");
map.put(new Integer(22), "a");
map.put(new Integer(33), "a");
map.put(new Integer(44), "a");
map.put(new Integer(55), "a");
map.put(new Integer(66), "a");
//1.1、1行表达式
map.forEach((key, value) -> System.out.println(key + ":" + value));
//1.2、多行表达式【需要用{}包裹!】
map.forEach((key, value) -> {
//System.out.println("---111---");
System.out.print(key + ":" + value + "、");
//System.out.println("---222---");
});
System.out.println();
//2、key存在,输出key对应的value值;key不存在,输出默认值defaultValue
System.out.println(map.getOrDefault("11", "***"));
System.out.println(map.getOrDefault(new Integer(11), "***"));
System.out.println(map.getOrDefault(new Integer(12), "***"));
}
}