java——HashMap

目录

前言:

1.创建Map的对象

2.添加元素

3.删除元素

4.清空数据

5.判断是否包含

6.获取集合的长度

7.迭代器

8.增强for

9.​​​Lamdba表达式

10.Enterset方法

11.HashMap的扩容操作是怎么实现的?

11.1 JDK1.7扩容

11.2 JDK1.8扩容

最后:


前言:

在 Java 编程的浩瀚世界中,数据结构的选择和运用至关重要。而 HashMap 作为 Java 集合框架中的一个核心数据结构,在众多应用场景中发挥着举足轻重的作用。

1.创建Map的对象

Map<String, String> m = new HashMap<>();//这里要用MAp的实现类HashMap来创建新的对象

2.添加元素

m.put("郭靖", "黄蓉");
m.put("韦小宝", "沐剑屏");
m.put("尹志平", "小龙女");

String result = m.put("韦小宝", "霜儿");
//此时霜儿就会把沐剑屏给覆盖
//返回的String的值会是被覆盖的沐剑屏,如果说没有被覆盖的值,就会返回null

System.out.println(result);

System.out.println("-------------------");

3.删除元素

String result1 = m.remove("郭靖");
System.out.println(result1);//返回的是他的”值“,也就是黄蓉,如果删除的是黄蓉,返回的是null,对集合中的元素没有影响
System.out.println("--------------remove------------");

4.清空数据

m.clear();

5.判断是否包含

//判断键是否存在
boolean result3 = m.containsKey("郭靖");
System.out.println(result3);
//判断值是否存在
boolean result4 = m.containsValue("小龙女");
System.out.println(result4);

6.获取集合的长度

int Size=m.size();
System.out.println(Size);
System.out.println(m);

7.迭代器

Iterator<String> it = keys.iterator();
while (it.hasNext()) {
    String key = it.next();//获取他的键
   String s= m.get(key);//获取它的值
    System.out.println(key+"="+s);
}
System.out.println("-----------------");

8.增强for

for (String k : keys) {
    String s = m.get(k);
    System.out.println(k+"="+s);
}


9.​​​Lamdba表达式

map.forEach(( student,  s)-> System.out.println(student+" "+s));


10.Enterset方法

Set<Map.Entry<student, String>> entries = map.entrySet();//将集合中的每一个键值对提取出来放到新的set集合中
for (Map.Entry<student, String> entry : entries) {
    student key=entry.getKey();
    String str1=key.toString();
    String str = entry.getValue();
    System.out.println(str1+"="+str);
}

11.HashMap的扩容操作是怎么实现的?

不管是JDK1.7或者JDK1.8 当put方法执行的时候,如果table为空,则执行resize()方法扩容。默认长度为16。

11.1 JDK1.7扩容

条件:发生扩容的条件必须同时满足两点

1.当前存储的数量大于等于阈值
2.发生hash碰撞

因为上面这两个条件,所以存在下面这些情况

就是hashmap在存值的时候(默认大小为16,负载因子0.75,阈值12),可能达到最后存满16个值的时候,再存入第17个值才会发生扩容现象,因为前16个值,每个值在底层数组中分别占据一个位置,并没有发生hash碰撞。
当然也有可能存储更多值(超多16个值,最多可以存26个值)都还没有扩容。原理:前11个值全部hash碰撞,存到数组的同一个位置(这时元素个数小于阈值12,不会扩容),后面所有存入的15个值全部分散到数组剩下的15个位置(这时元素个数大于等于阈值,但是每次存入的元素并没有发生hash碰撞,所以不会扩容),前面11+15=26,所以在存入第27个值的时候才同时满足上面两个条件,这时候才会发生扩容现象。
特点:先扩容,再添加(扩容使用的头插法)

缺点:头插法会使链表发生反转,多线程环境下可能会死循环

扩容之后对table的调整:

table容量变为2倍,所有的元素下标需要重新计算,newIndex = hash (扰动后) & (newLength - 1)

11.2 JDK1.8扩容

条件:

当前存储的数量大于等于阈值
当某个链表长度>=8,但是数组存储的结点数size() < 64时
特点:先插后判断是否需要扩容(扩容时是尾插法)

缺点:多线程下,1.8会有数据覆盖

举例:

线程A:往index插,index此时为空,可以插入,但是此时线程A被挂起
线程B:此时,对index写入数据,A恢复后,就把B数据覆盖了

扩容之后对table的调整:

table容量变为2倍,但是不需要像之前一样计算下标,只需要将hash值和旧数组长度相与即可确定位置。

如果 Node 桶的数据结构是链表会生成 low 和 high 两条链表,是红黑树则生成 low 和 high 两颗红黑树
依靠 (hash & oldCap) == 0 判断 Node 中的每个结点归属于 low 还是 high。
把 low 插入到 新数组中 当前数组下标的位置,把 high 链表插入到 新数组中 [当前数组下标 + 旧数组长度] 的位置
如果生成的 low,high 树中元素个数小于等于6退化成链表再插入到新数组的相应下标的位置

最后:

通过对 Java HashMap 的深入探讨,我们可以清晰地看到它在 Java 编程中的重要性和广泛适用性。从简单的数据存储到复杂的业务逻辑处理,HashMap 都能为我们提供高效、便捷的解决方案。

在不断发展的 Java 生态中,我们应持续深入学习和掌握各种数据结构的特点和用法,以便在实际开发中做出更加明智的选择。希望本博客能为你在使用 Java HashMap 时提供有价值的参考和启发,助力你在 Java 编程的道路上更加自信地前行。期待你在未来的编程之旅中创造出更加精彩的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值