Java Map学习笔记:HashMap、LinkedHashMap 与 TreeMap 的核心使用与区别

Java内置的集合框架,除了提供Collection单列集合外,还提供所谓双列集合Map,即所谓存储"键值对"的集合。键和值是两个对象,而键值对在Java中称为entry。

与Collection相似,Map是一个接口,有HashMap、LinkedHashMap和TreeMap三种实现类,这三种实现类与Set的三种实现类(HashSet、LinkedHashSet和TreeSet)在底层实现上相同。实际上,Map只是比Set增加了一个"值对象"。准确来说,HashSet的内部实现基于 HashMap,将其值视为一个固定值。因此,Map具有与Set相似特点:不保证顺序、键不可重复(但值可重复)、不可索引。

Map的方法与Set也很相似,但是额外多了有关值的方法。Map常见方法如下:

java 复制代码
V put(K key, V value);           // 添加键值对,如果键存在会返回旧值,如果键不存在则返回null
V remove(Object key);             // 删除键值对,返回旧值。若键不存在则返回null
boolean remove(Object key, Object value); // 删除指定键值对
void clear();                     // 清空Map
V get(Object key);                // 获取指定键的值
boolean containsKey(Object key);  // 是否包含键
boolean containsValue(Object value); // 是否包含值
int size();                       // 元素数量
boolean isEmpty();                // 是否为空

对常见方法的代码演示如下:

java 复制代码
public class Demo0 {  
    public static void main(String[] args) {  
        // 创建Map集合对象  
        Map<String, String> map = new HashMap<>();  
  
        // boolean isEmpty(); 判断集合是否为空  
        System.out.println(map.isEmpty()); // true  
  
        // V put(K key, V value); 添加键值对,如果键存在会返回旧值,同时覆盖旧值,如果键不存在则返回null  
        System.out.println(map.put("郭靖", "黄蓉")); // null  
        System.out.println(map.put("杨过", "小龙女")); // null  
        System.out.println(map.put("韦小宝", "沐剑屏")); // null  
        System.out.println(map.put("韦小宝", "阿珂")); // 沐剑屏  
  
        System.out.println(map); // {郭靖=黄蓉, 杨过=小龙女, 韦小宝=阿珂}  
  
        // int size(); 获取键值对数量  
        System.out.println(map.size()); // 3  
        System.out.println(map.isEmpty()); // false  
  
        // boolean containsKey(Object key); 判断集合中是否包含指定的键  
        System.out.println(map.containsKey("郭靖")); // true  
        System.out.println(map.containsKey("小龙女")); // false  
  
        // boolean containsValue(Object value); 判断集合中是否包含指定的值  
        System.out.println(map.containsValue("阿珂")); // true  
        System.out.println(map.containsValue("沐剑屏")); // false  
  
        // V remove(Object key); 删除键值对,返回旧值。若键不存在则返回null  
        System.out.println(map.remove("郭靖")); // 黄蓉  
        System.out.println(map.remove("小龙女")); // null  
    }  
}

Map的遍历有三种方式:

  1. 通过键找值:获取Map中的所有key为新Set,再通过key找到value。
  2. 通过键值对:获取Map中的键值对对象成一个新Set,再遍历键值对对象找key、value。
  3. 使用foreach方法用lamda表达式
java 复制代码
public class Demo1 {  
    public static void main(String[] args) {  
        // 创建Map集合  
        Map<String, String> map = new HashMap<>();  
  
        // 添加元素  
        map.put("郭靖", "黄蓉");  
        map.put("杨过", "小龙女");  
        map.put("韦小宝", "沐剑屏");  
  
        // 遍历方法1: 通过键找值:获取Map中的所有key为新单列集合,再通过key找到value。  
        Set<String> keys = map.keySet(); // keySet()方法获取Map中的所有key集合  
        for (String key : keys) {  
            String value = map.get(key); // get(key)方法通过key找到value  
            System.out.println(key + "=" + value);  
        }  
  
        System.out.println("---------分割线-----------");  
  
        // 遍历方法2: 通过键值对:获取Map中的键值对对象成一个新单列集合,再遍历键值对对象找key、value。  
        Set<Map.Entry<String, String>> entries = map.entrySet(); // entrySet()方法获取Map中的键值对对象集合  
        for (Map.Entry<String, String> entry : entries) {  
            String key = entry.getKey(); // Entry对象的getKey()方法获取key  
            String value = entry.getValue(); // Entry对象的getValue()方法获取value  
            System.out.println(key + "=" + value);  
        }  
  
        System.out.println("---------分割线-----------");  
  
        // 遍历方法3: 通过foreach方法  
        map.forEach((key, value) -> System.out.println(key + "=" + value));  
    }  
}

HashMap

HashMap是Map的实现类,底层使用哈希表。

HashMap与HashSet相似,HashSet节点Node中存储的内容是元素本身,而HashMap存储的内容是键值对对象,又称为Entry对象。

HashMap的元素插入逻辑:

  1. 将键和值两个对象,组成一个键值对Entry对象
  2. 用键调用hashCode()方法,计算键的哈希值
  3. 通过哈希值和哈希表数组的长度,计算数组索引值
  4. 若数组为null,则存储键值对对象
  5. 若数组不为null,则调用equals()方法,逐一判断链表中已存在的键值对的键,是否相等
  6. 若键相同,则覆盖键值对对象
  7. 若链表中的键都不同,则最后插入到链表尾部。

因此,若用HashMap,与HashSet相似,需要重写键类的hashCode()和equals()方法。

LinkedHashMap

LinkedHashMap是Map的实现类,底层使用哈希表。

LinkedHashMap与HashMap的关系,就跟LinkedHashSet与HashSet的关系相似,LinkedHashMap是在HashMap的节点基础上,增加了指向上一个插入元素Entry对象的节点和指向下一个插入元素Entry对象的节点。

因此,LinkedHashMap特点是有序、键不重复、不可索引。如下可以看出,遍历获取的顺序与插入顺序相同:

java 复制代码
public class Demo2 {  
    public static void main(String[] args) {  
        // 创建一个Map集合对象  
        Map<Student, String> map = new LinkedHashMap<>();  
  
        // 添加三个元素  
        map.put(new Student("张三", 18), "成都");  
        map.put(new Student("李四", 19), "上海");  
        map.put(new Student("王五", 20), "北京");  
  
        // 遍历键值对  
        for (Map.Entry<Student, String> entry : map.entrySet()) {  
            System.out.println(entry.getKey() + "=" + entry.getValue());  
        }  
    }  
}
shell 复制代码
Student{name='张三', age=18}=成都
Student{name='李四', age=19}=上海
Student{name='王五', age=20}=北京

进程已结束,退出代码为 0

TreeMap

TreeMap是Map的实现类,底层使用红黑树。

TreeMap与TreeSet相似,HashSet节点Node中存储的内容是元素本身,而HashMap存储的内容是键值对对象,又称为Entry对象。

树这一数据结构要求存储的元素需要能够比较,因此TreeMap存储的键值对对象的键也需要支持比较。

相关推荐
2501_941870568 小时前
从配置频繁变动到动态配置体系落地的互联网系统工程实践随笔与多语言语法思考
java·前端·python
民乐团扒谱机8 小时前
【微实验】数模美赛备赛MATLAB实战:一文速通各种“马尔可夫”(Markov Model)
开发语言·人工智能·笔记·matlab·数据挖掘·马尔科夫链·线性系统
菜的不敢吱声9 小时前
swift学习第2,3天
python·学习·swift
宵时待雨9 小时前
数据结构(初阶)笔记归纳1:复杂度讲解
c语言·数据结构·笔记
l04090442229 小时前
想学习VLN相关的知识,并亲手搭建一套系统,该如何入手?
学习
她说..9 小时前
Spring 核心工具类 AopUtils 超详细全解
java·后端·spring·springboot·spring aop
今儿敲了吗9 小时前
第二章 C++对C的核心拓展
c++·笔记
TH_19 小时前
33、IDEA无法获取最新分支
java·ide·intellij-idea
极客先躯9 小时前
Java Agent 技术全解析:从基础框架到落地实践
java·开发语言
yaso_zhang9 小时前
linux 下sudo运行程序,链接找不到问题处理
java·linux·服务器