Java集合框架详解(四)——Map接口、HashMap类、LinkedHashMap类

news2025/7/19 11:12:55

一、Map接口

  1. Map接口的特点:

(1)映射键值对的形式(key和value);
(2)Map集合中,key是不能重复的,value是可以重复的;
(3)Map集合是散列存放数据的,所以存储顺序与遍历顺序是无序的,即遍历顺序可能与存储顺序不一致。

  1. Map集合的获取方法:
方法名称说明
V get(Object key)根据key获取值
Set keySet()获取所有健的集合
Collection values()获取所有值的集合
Set<Map.Entry<K,V> entrySet()获取所有健值对象的集合
default V getOrDefult(Object key, V defaultValue)如果存在相应的key则返回其对应的value,否则返回给定的默认值defaultValue
eg:
public static void main(String[] args) {
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put("qize01", "小丽");
        hashMap.put("qize02", "天天");
        hashMap.put("qize03", "阿奇");
        hashMap.put("qize04", "毛毛");
        //1、根据键获取值
        System.out.println(hashMap.get("qize01"));
        System.out.println(hashMap.get("ss"));
        //2、获取所有健的集合
        Set<String> stringSet = hashMap.keySet();
        for (String key:stringSet){
            System.out.println(key);
        }
        //3、获取所有value的集合
        Collection<String> values = hashMap.values();
        for (String value:values){
            System.out.println(value);
        }
        //4、获取所有键值对象的集合
        Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
        for (Map.Entry<String, String> entry:entrySet){
            System.out.println(entry);
        }
        //5、如果存在相应的key,则返回其对应的value,否则返回给定的默认值defaultValue
        String qize01 = hashMap.getOrDefault("qize0001","默认值");
        System.out.println(qize01);
 }

二、HashMap类

1、HashMap类特点:
(1)HashMap类实现Map接口;
(2)HashMap类是散列存放数据的,所以存储顺序与遍历顺序是无序的,即遍历顺序可能与存储顺序不一致。
(3)HashMap:底层是基于数组+链表结构来实现的(JDK1.7);基于数组+链表+红黑树实现的(JDK1.8);是线程不安全的。

eg:

Map<String,String> hashMap = new HashMap<>();
hashMap.put("qize001","天天");
hashMap.put("qize002","小丽");
hashMap.put("qize003","莱德");
hashMap.put("qize004","古薇");
System.out.println(hashMap);

2、HashMap类常用方法

方法名称解释
V put(K key, V value)添加元素
V remove(K key, V value)根据健值删除对应的值
void clear()清除所有健值元素
boolean containsKey(Object key)判断集合中是否包含指定的健
boolean containsValue(Object value)判断集合中是否包含指定的值
boolean isEnpty()判断集合是否为空

eg:

public static void main(String[] args) {
	Map<String, String> hashMap = new HashMap<>();
    //put方法
    hashMap.put("qize001","天天");
    hashMap.put("qize002","阿奇");
    hashMap.put("qize003","小丽");
    System.out.println(hashMap);
    System.out.println("------------------");
    //判断集合中是否包含指定的健
    System.out.println(hashMap.containsKey("qize002"));
    //判断集合中是否包含指定的值
    System.out.println(hashMap.containsValue("小丽"));
    //根据健值删除对应的值
    hashMap.remove("qize002");
    System.out.println(hashMap);
    //判断集合是否为空
    System.out.println(hashMap.isEmpty());
    //清除所有健值元素
    hashMap.clear();
    System.out.println(hashMap);
    //判断集合是否为空
    System.out.println(hashMap.isEmpty());
}

3、HashMap集合的遍历
(1)先取到HashMap集合中所有的键,再通过增强for循环调用get方法获取对应的value值:
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<String> keySet = hashMap.keySet();
    for (String key:keySet){
        String value = hashMap.get(key);
        System.out.println(key+"-"+value);
    }
}

(2)使用entrySet() 方法获取所有健值对象的集合
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
    for(Map.Entry<String, String> entry:entrySet){
        System.out.println(entry.getKey()+"-"+entry.getValue());
    }
 }

(3)使用entrySet() 方法和 Iterator 获取所有健值对象的集合
eg:

public static void main(String[] args) {
    HashMap<String,String> hashMap = new HashMap<>();
    hashMap.put("qize01","毛毛");
    hashMap.put("qize02","天天");
    hashMap.put("qize03","阿奇");
    Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
    Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
    while (iterator.hasNext()){
        Map.Entry<String, String> entry = iterator.next();
        System.out.println(entry.getKey()+"-"+entry.getValue());
    }
}

4、HashMap集合的底层原理
(1)HashMap 的 key 是否可以设置为自定义对象?可以。
(2)HashMap 存储数据时有序还是无序的?是无序的。
(3)HashMap 是否可以存放null 值?如果可以的话,存放在数组中哪个位置呢?可以存放null值,存放在数组index为0的位置。
(4)HashMap 集合中键值对是如何封装的?是通过实现Map接口封装的Entry对象来封装的。
eg:

public static void main(String[] args) {
    //HashMap 的 key 是否可以设置为自定义对象?可以。
    Student student = new Student("qize01",32);
    HashMap<Student, String> hashMap1 = new HashMap<>();
    hashMap1.put(student, "qize");
    //HashMap 存储数据时有序还是无序的?是无序的。
    HashMap<String, String> hashMap2 = new HashMap<>();
    for (int i=0;i<20; i++){
        hashMap2.put("qize"+i, "i:"+i);
    }
    hashMap2.forEach((k,v) -> {
        System.out.println(k+","+v);
    });
    //HashMap 是否可以存放null 值?如果可以的话,存放在数组中哪个位置呢?
    //可以存放null值,存放在数组index为0的位置
    HashMap<String, String> hashMap3 = new HashMap<>();
    hashMap3.put(null,"毛毛");
}

(5)key的hash算法原理
hashMap集合 1.7版本 是基于数组+链表实现的
hashMap集合 1.8版本 是基于数组+链表+红黑树实现的
根据key的hashCode 取余entrys.length,得到的余数就是该key存放在我们数组中对应的index位置
eg:

public class QizeHashMap<K, V> {
    private  Entry[] entrys = new Entry[10000];

    class Entry<K, V> {
        K k;//key
        V v;//value

        int hash;//key的hash值

        public Entry(K k, V v) {
            this.k = k;
            this.v = v;
        }
    }
    
    public  void put(K k, V v){
        //根据key的hashCode 取余entrys.length
        //得到的余数就是该key存放在我们数组中对应的index位置
        int index = k.hashCode() % entrys.length;
        entrys[index] = new Entry<>(k, v);
    }

    public V get(K k){
        //如果根据key查询的话,hashCode 取余entrys.length
        int index = k.hashCode() % entrys.length;
        return (V) entrys[index].v;
    }

    public static void main(String[] args) {
        QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
        hashMap.put("qize", "毛毛");
        System.out.println(hashMap.get("qize"));
    }
}

(6)什么是hash冲突问题?
hashCode相同但是值不同,例如 key=“a” 和key=97 最终计算的存放value的下标index相同,则key=97的存放在数组的键值对(Entry对象)会覆盖掉key="a"存放在数组中的键值对。
eg:

//在(5)key的hash算法原理的例子的基础上修改main方法,如下
public static void main(String[] args) {
    QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
    hashMap.put("a", "毛毛");
    hashMap.put(97, "小丽");
    System.out.println(hashMap.get("a"));
}

运行得到的打印结果为 “小丽” ,而不是 “毛毛” ,这就是hash冲突问题。
在这里插入图片描述
怎么解决hash冲突问题?
在JDK 1.7中是通过链表来解决的。
先判断该index位置 是否有存放键值对(Entry对象),如果取出结果为null,则表示此index位置没有存放数据,则可以直接存放,如果取出的结果为一个Entry对象,则表示此处有hash冲突,需要进行处理。
故上述“(5)key的hash算法原理的例子”可以优化为如下:

public class QizeHashMap<K, V> {
    private  Entry[] entrys = new Entry[10000];

    class Entry<K, V> {
        K k;//key
        V v;//value

        int hash;//key的hash值
        Entry<K, V> next;//Entry的下一个节点

        public Entry(K k, V v, int hash) {
            this.k = k;
            this.v = v;
            this.hash = hash;
        }
    }

    public  void put(K k, V v){
        //根据key的hashCode 取余entrys.length
        //得到的余数就是该key存放在我们数组中对应的index位置

        /**
         * 1、先判断该index位置 是否有存放数据
         * 2、如果取出结果为null,则表示此index位置没有存放数据,则可以直接存放
         * 3、如果取出的结果为一个Entry对象,则表示此处有hash冲突,需要进行处理
         */
        int hash = k.hashCode();
        int index = hash % entrys.length;
        Entry oldEntry = entrys[index];
        if(oldEntry == null){
            entrys[index] = new Entry<>(k, v, hash);
        }else {
            oldEntry.next = new Entry<>(k, v, hash);
        }

    }

    public V get(K k){
        //如果根据key查询的话,hashCode 取余entrys.length
        int hash = k.hashCode();
        int index = hash % entrys.length;
        for (Entry<K, V> entry = entrys[index]; entry != null; entry = entry.next){
            if(entry.hash == hash && (entry.k == k || entry.k.equals(k))){
                return entry.v;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        QizeHashMap<Object, Object> hashMap = new QizeHashMap<>();
        hashMap.put("a", "毛毛");
        hashMap.put(97, "小丽");
        System.out.println(hashMap.get("a"));
    }
}

三、hashCode方法与equals方法

  1. 如果两个对象equals相等,那么这两个对象的HashCode一定也相同;
  2. 如果两个对象的hashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置;
  3. 如果对象的equals方法被重写,那么对象的hashCode方法也尽量重写;
  4. String的equals方法验证的是两个字符串的值是否一样。

eg:

public class Student {
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @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 static void main(String[] args) {
    /**
     *  equals 属于 object父类中,默认的情况下 在比较两个对象的内存地址是否相同
     *  两个字符串equals 是比较两个对象的值是否相等,因为String类重写了equals方法
     */
    String str1 = "qize";
    String str2 = "qize";
    System.out.println(str1.equals(str2));
    System.out.println("--------------------");
    Student student1 = new Student("qize",22);
    Student student2 = new Student("qize",22);
    System.out.println(student1.equals(student2));
    System.out.println(student1.hashCode());
    System.out.println(student2.hashCode());
}

四、LinkedHashMap集合

LinkedHashMap 继承自HashMap,它的多种操作都是建立在HashMap操作的基础上的,与HashMap不同的是,LinkedHashMap 维护了一个Entry 的双向链表,保证了插入的Entry 中的顺序。
eg:

public static void main(String[] args) {
    LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
    for(int i=1; i<=100; i++){
        linkedHashMap.put("k:"+i,"v:"+i);
    }
    for (Map.Entry<String, String> entry:linkedHashMap.entrySet()){
        System.out.println(entry.getKey()+","+entry.getValue());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/37862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决报错:fatal: Authentication failed for ‘https://github.com/*/*.git/‘

目录 问题 解决 步骤一、 步骤二、 步骤三、 ​步骤四、 ​步骤五、 步骤六、 问题 今天创建一个 github 新仓库&#xff0c;首次上传本地代码时&#xff0c;遇到了一个报错。但是&#xff0c;之前这样操作肯定是没有问题的&#xff0c;毕竟我可以保证用户名和密码都是…

复杂环境下多移动机器人路径规划研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

数据结构 | 顺序栈与链式队【栈与队列的交际舞】

数据结构之栈与队列&#x1f333;顺序栈&#x1f343;前言&#x1f525;栈的结构简介及概述&#x1f525;为什么要用顺序栈&#xff1f;&#x1f525;结构声明&#x1f343;接口算法实现&#x1f35e;初始化栈&#x1f35e;销毁栈&#x1f35e;入栈&#x1f35e;出栈&#x1f3…

磨金石教育|干货分享:剪辑技法之跳切(上)

有一种剪辑手法划分了传统剪辑与现代剪辑的界限&#xff0c;它就是“跳切”&#xff1b; 跳切&#xff0c;是“切”的一种。属于一种无技巧的剪辑手法。它打破常规状态镜头切换时所遵循的时空和动作连续性要求&#xff0c;以较大幅度的跳跃式镜头组接&#xff0c;突出某些必要内…

【kafka】三、kafka命令行操作

kafka命令行操作 kafka的相关操作命令脚本文件在bin目录下 查看所有的topic kafka-topics.sh --zookeeper hll1:2181 --list 或 kafka-topics.sh --zookeeper 192.168.171.132:2181 --listkafka-topics.sh&#xff1a;topic执行脚本 --zookeeper hll1:2181&#xff1a;需要的…

[carla]把carla世界坐标系 转换为 俯视地图像素坐标系

在下面这篇参考博客中介绍了如何手动获取从carla世界坐标系到俯视地图像素坐标系的旋转平移矩阵.我也是采用了一样的思路和代码,这里把实现的过程以及最后所有地图的变换矩阵记录如下. 参考博客:carla真实世界坐标系与全局俯视地图像素坐标系变换 文章目录代码:1.carla世界坐标…

【表白】html表白代码

目录一.引言二.表白效果展示1.惊喜表白2.烟花表白3.玫瑰花表白4.心形表白5.心加文字6.炫酷的特效一.引言 我们可以用一下好看的网页来表白&#xff0c;下面就有我觉得很有趣的表白代码 下载整套表白文件 二.表白效果展示 1.惊喜表白 2.烟花表白 源码&#xff1a;新建一个文本文…

基于51单片机的温度控制系统数码管显示蜂鸣器报警proteus仿真原理图PCB

功能&#xff1a; 0.本系统采用STC89C52作为单片机 1.系统实时监测并显示当前温度&#xff0c;并通过四位数码管显示 2.超过设定阈值&#xff0c;蜂鸣器将报警&#xff0c;同时控制相应继电器实现降温或者加热 3.系统具备三个功能按键&#xff0c;可更改温度上限和下限 4.采用D…

SpringBoot+Mybatis-Plus+Thymeleaf 实现增删改查+登录/注册

SQL -- student_info create table if not exists student_info ( sid int not null auto_increment comment 学生表主键 primary key, sname varchar(20) not null comment 学生账号登录名、姓名, pwd varchar(32) not null comment 密码, sex varchar(20) not null comment …

AQS源码解析 7.共享模式_CyclicBarrier重复屏障

AQS源码解析 —共享模式_CyclicBarrier重复屏障 简介 CyclicBarrier&#xff1a;循环屏障、循环栅栏&#xff0c;用来进行线程协作&#xff0c;等待线程满足某个计数。构造时设置『计数个数』&#xff0c;每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待&…

【多目标进化优化】多目标进化群体的分布性

0 前言 \quad\quad进化算法是模拟生物自然进化的人工方法&#xff0c;与大自然生态环境一样&#xff0c;进化的物种也需要平衡发展。因此&#xff0c;设计者必须制定合适的生存规则来维持种群的多样性和分布性。在多目标进化算法中&#xff0c;对于某些问题&#xff0c;Pareto最…

微机-------可编程并行接口8255A

目录 8255A的内部结构8255A控制信息和传输动作的对应关系⭐8255A的控制字一、方式选择控制字①方式0(基本输入输出工作方式)二、端口C置1/置0控制字8255A的工作方式②方式1(选通的输入输出工作方式)③方式2(双向传输方式)⭐⭐8255的编程及应用8255A的内部结构 ①数据总线…

Steam项目推进(二)—— 在项目中使用FairyGUI

一、遇到的问题 昨天把代码大致清理了一遍之后&#xff0c;发现代码中存在很大的一个问题是数据和表现耦合在一起了&#xff0c;如下&#xff1a; using UnityEngine; using UnityEngine.UI;public enum CardStateType {InDeck, InHand, InBattle, InSave, InAbandon }//卡牌…

Cisco简单配置(十八)—OSPF

开放式最短路径优先&#xff08;Open Shortest Path First&#xff0c;OSPF&#xff09;是广泛使用的一种动态路由协议&#xff0c;它属于链路状态路由协议&#xff0c;具有路由变化收敛速度快、无路由环路、支持变长子网掩码&#xff08;VLSM&#xff09;和汇总、层次区域划分…

设计模式-组合模式(决策树)

一、只如初见 组合模式也许大家第一联想到的就是把两个模块组合起来使用&#xff0c;其实好像是这样也其实不是这样&#xff0c;废话不多说&#xff0c;学习一件新的事物总要先了解一下他的概念&#xff0c;老规矩先上概念&#xff08;摘自百度百科&#xff09;&#xff1a; 组…

【活动预告】金融大数据治理实践分享(12/03)

原创 DAMA数据管理 # 本期主题 金融大数据治理实践分享 数字化时代&#xff0c;数据的价值受到越来越多的关注&#xff0c;有人将其比作黄金&#xff0c;也有人将其比作石油&#xff0c;成为组织中的最重要资产之一。针对数据这种有特殊属性的资产&#xff0c;也存在着采集…

[论文阅读] 颜色迁移-N维pdf迁移

[论文阅读] 颜色迁移-N维pdf迁移 文章: N-Dimensional Probability Density Function Transfer and its Application to Colour Transfer, [paper ][code] 1-算法原理 简单来说, 本文将图像看作是随机变量的一组样本, 图像之间的颜色迁移可以看作是样本之间分布的迁移. 因而…

G1D23-RAGA报名蓝桥Attackg安装cudatorch

昨天太摸鱼啦~不过蛮开心的哈哈 今天主要是把积累的ddl都清理一下&#xff01;&#xff01;&#xff01;第一项就是我和舍友一起读的论文嘿嘿&#xff01;&#xff01; 一、RAGA &#xff08;零&#xff09;总结&#xff08;仅模型&#xff09; 作为数据挖掘顶会2021年的论文…

【MATLAB教程案例46】三维数据的插值和滤波处理matlab仿真

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 本课程学习成果预览: 目录 1.软件版本 2.三维数据插值

openFeign夺命连环9问,这谁受得了?

1、前言 前面介绍了Spring Cloud 中的灵魂摆渡者Nacos&#xff0c;和它的前辈们相比不仅仅功能强大&#xff0c;而且部署非常简单。 今天介绍一款服务调用的组件&#xff1a;OpenFeign&#xff0c;同样是一款超越先辈&#xff08;Ribbon、Feign&#xff09;的狠角色。 文章目…