HashMap基本使用

特点:

①HashMap是Map里面的一个实现类。
②没有额外需要学习的特有方法,直接使用Map里面的方法就可以了。
特点都是由键决定的:无序、不重复、无索引
④HashMap跟HashSet底层原理是一模一样的,从名字可以看出来,都是哈希表结构


底层原理:

jdk8 及以后的 HashMap 的底层原理。

  1. 创建 HashMap 集合后,会在底层创建一个长度为 16 的数组 table,并加载 负载因子为0.75 的 HashMap
    1. 这意味着当 HashMap 中的元素数量达到数组长度的 75% 时,数组会进行扩容(原有长度*2)操作,以保持较低的碰撞率和良好的性能。
    2. 为什么加载因子是0.75?【面试题】:这个值是根据空间和时间,通过泊松分布算法得到的一个折中的值。
  2. **根据元素的键计算哈希值(和值无关)**跟数组的长度计算出应存入的位置

int index=( 数组长度-1 ) & 哈希值
所以说第一个元素存入的位置不一定是 0 索引处,如下
image.png
获取元素时就从左到右遍历,所以说 HashMap 是无序的

  1. 判断当前位置是否为 null,如果是 null 直接存入
    1. 如果不是 null,表示有元素,这时则调用 equals 方法比较 键

注意这里和 HashSet 不太一样

  1. **如果键值是一样的,那么就会覆盖原有的Entry对象,不一样则存入,形成链表**
     1. 注意: jdk8 以前:新元素存入数组,老元素挂在新元素下面,jdk8及以后:新元素直接挂在老元素下面。如图:
     2. ![image.png](https://cdn.nlark.com/yuque/0/2024/png/40571611/1706352453975-788390f9-db34-4e6e-a341-6ca13d7e95da.png#averageHue=%23f5f4f4&clientId=u5ed0c2fb-24ca-4&from=paste&height=251&id=u205b9bc9&originHeight=377&originWidth=284&originalType=binary&ratio=1.5&rotation=0&showTitle=false&size=25649&status=done&style=shadow&taskId=u5d0fab22-0e25-4769-a0a2-69fd04fdb17&title=&width=189.33333333333334)
  2. 注意:当链表长度大于 8  **并且**  数组长度 >= 64 时,链表会变成红黑树。如图:
  3. ![image.png](https://cdn.nlark.com/yuque/0/2024/png/40571611/1706352648228-7a43a3dd-f57d-4ce8-bd1d-40be46bc18b4.png#averageHue=%23f5efed&clientId=u5ed0c2fb-24ca-4&from=paste&height=378&id=ua663b5fc&originHeight=567&originWidth=1244&originalType=binary&ratio=1.5&rotation=0&showTitle=false&size=152634&status=done&style=shadow&taskId=udc3c2a2c-409d-486a-882d-70c76bed134&title=&width=829.3333333333334)

  • 重写 hashCode 是为了通过键计算哈希值,而不是地址值
  • 重写 equals 是为了比较对象内部属性,

总结:

1.Hash Map底层是哈希表结构的
2.依赖hash Code方法和equals方法保证键的唯一
3.如果键存储的是自定义对象,需要重写hash code和equals方法
如果值存储自定义对象,不需要重写 hash code和equals方法


HashMap 练习 1:存储自定义对象

Snipaste_2024-01-29_10-24-27.png

Student

package com.lt.arr.map.hashmap;

import java.util.Objects;

public class Student {
    private String name;
    private int age;



   // 构造+set+get+toString
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

测试类

public class Test01 {
    public static void main(String[] args) {
//创建HashMap集合对象
HashMap<Student, String> m = new HashMap<>();
//添加键值对
m.put(new Student("zhangsan", 23), "jiangxi");
m.put(new Student("lisi", 24), "beijing");
m.put(new Student("zhangsan", 23), "shanghai");//键重复,覆盖

//遍历
//keySet
Set<Student> stu = m.keySet();
for (Student student : stu) {
    System.out.println(student + " -" + m.get(student));
}

//EntrySet
Set<Map.Entry<Student, String>> set = m.entrySet();
for (Map.Entry<Student, String> Entry : set) {
    System.out.println(Entry.getKey()+"- " + Entry.getValue());
}

//Lambda表达式
m.forEach((Student ,String) -> System.out.println(Student+"- "+String));
    }
}

Student{name = lisi, age = 24} -beijing
Student{name = zhangsan, age = 23} -shanghai

image.png
若未重写 hashCode 和 equals 方法计算哈希值时


HashMap 练习 2:利用 Map 集合进行统计:

Snipaste_2024-01-29_10-25-19.png

package com.lt.arr.map.hashmap;

import java.util.*;

public class Test02 {
    public static void main(String[] args) {
    //80名同学用for循环模拟、投票可以用随机数实现、
    Random r=new Random();
    //景点用数组存储;
    String[]Attractions={"A","B","C","D"};
    //投票结果用集合存储
    ArrayList<String>list=new ArrayList<>();
    //循环80次  模拟投票场景
    for (int i = 0; i < 80; i++) {
        int index = r.nextInt(Attractions.length);//0-3
        list.add(Attractions[index]);
    }


    //如果要统计的东西比较多,不方便使用计数器思想
    //用HashMap存储对应关系,键是景区,值是票数,谁多谁少显而易见
    HashMap<String,Integer>map=new HashMap<>();
    //遍历list集合
    for (String attractions : list) {
        if (map.containsKey(attractions)){
//若map内存在当前景点,说明已经有人投票了,只需拿出次数+1,再放入即可
            Integer count = map.get(attractions);
            count++;
            map.put(attractions,count);
        }else {
            //map内无该景点时
            map.put(attractions,1);
        }
    }

    //entrySet遍历集合
    Set <Map.Entry<String ,Integer>> set=  map.entrySet();

    for (Map.Entry<String, Integer> entry : set) {
        System.out.println(entry.getKey()+" "+entry.getValue());
    }

    //获取最大的值;
    int max=0;
    for (Map.Entry<String, Integer> entry : set) {
        if (entry.getValue()>max){
            max= entry.getValue();
        }
    }
    System.out.println(max);

    //将最大值的键打印出来
    for (Map.Entry<String, Integer> entry : set) {
        if (entry.getValue()==max){
            System.out.println(entry.getKey()+"景点想去的人最多"+"有"+max+"人");
        }
    }

    }
}

A 20
B 26
C 18
D 16
26
B景点想去的人最多有26人

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成果、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值