JAVA 集合框架(四) Map集合详解和常用方法

Map集合是Java集合框架中的一个重要组成部分,它以键值对(key-value pairs)的形式存储数据。Map集合中的每个键都是唯一的,因此它不允许键的重复,而每个键可以关联一个值,同一键可以对应不同的值(在不改变键的情况下更新值)。Map 接口主要用于通过键快速查找、插入和删除对应的值。

Map接口的主要特征

  • 键-值存储 :Map集合中每个元素都是一个键值对(KeyValuePair),通常写作<K, V>,其中K代表键的类型,V代表值的类型。
  • 唯一键约束:Map集合的键必须唯一,也就是说,如果试图插入一个与现有键相同的键,原有的键值对将被新的键值对替换(如果值不同的话)。
  • 键的无序性 :Map集合中的元素不保证顺序,除非使用了如LinkedHashMap这样的有序Map实现类。
  • 常用操作 :Map集合提供了丰富的API来添加、删除、查找、更新键值对,如put(key, value)(添加或更新键值对)、get(key)(通过键获取值)、remove(key)(通过键删除键值对)、containsKey(key)(检查Map中是否存在指定键)等。

Map接口的主要实现类

  • HashMap
    • 基于哈希表的实现,它允许空键和空值。
    • 迭代顺序不是基于插入顺序的。
  • LinkedHashMap
    • HashMap 的子类,维护了一个双向链表,可以按照插入顺序或访问顺序来遍历键值对。
  • TreeMap
    • 基于红黑树的实现,可以按照自然顺序或自定义顺序对键进行排序。
  • Hashtable
    • HashMap 类似,但它是线程安全的,不允许空键和空值。
  • ConcurrentHashMap
    • 线程安全的 HashMap 实现,用于多线程环境。
  • IdentityHashMap
    • 使用 == 而不是 equals() 方法来比较键。

Map接口的主要方法

添加键值对

  • V put(K key, V value):向Map中添加键值对,如果键已存在,则旧值将被新值替换并返回旧值;如果键不存在,则添加新的键值对并返回null。
java 复制代码
// 创建一个 Map 集合
Map<String, Integer> myMap = new HashMap<>();
// 添加键值对
myMap.put("Apple", 1);
myMap.put("Banana", 2);
System.out.println(myMap); // 输出: {Apple=1, Banana=2}

获取值

  • V get(Object key):根据给定的键获取对应的值,如果键不存在,则返回null。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 获取值
Integer banana = myMap.get("Banana");
System.out.println(banana); // 输出: 2

删除键值对

  • V remove(Object key):删除指定键的键值对,如果键存在,则返回对应的值,否则返回null。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 删除键为"Apple"的键值对,并返回1
Integer removedValue  = myMap.remove("Apple");
System.out.println(removedValue);// 输出: 1
System.out.println(myMap);// 输出: {Pear=5, Mango=3, Orange=4, Banana=2}

判断键是否存在

  • boolean containsKey(Object key):判断Map中是否包含指定的键。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 判断 "Apple" 是否存在
boolean hasApple = myMap.containsKey("Apple");
System.out.println("键 Apple 是否存在: " + hasApple);// 输出: 键 Apple 是否存在: true

判断值是否存在

  • boolean containsValue(Object value):判断Map中是否包含指定的值。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 判断Value值 1 是否存在
boolean containsValue = myMap.containsValue(1);
System.out.println("值 1 是否存在? " + containsValue);// 输出: 值 1 是否存在? true

获取Map大小

  • int size():返回Map中键值对的数量。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 获取集合的大小
int mapSize = myMap.size();
System.out.println(mapSize);// 输出: 5

清空Map

  • void clear():删除Map中的所有键值对。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 清空Map
myMap.clear();
System.out.println(myMap);//输出: {}

获取所有键的集合

  • Set<K> keySet():返回一个包含所有键的Set集合。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 获得所有键的集合
Set<String> keys = myMap.keySet();
System.out.println(keys);//输出: [Apple, Pear, Mango, Orange, Banana]

获取所有值的集合

  • Collection<V> values():返回一个包含所有值的Collection集合。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 获取所有值的集合
Collection<Integer> values = myMap.values();
System.out.println(values);// 输出: [1, 5, 3, 4, 2]

获取键值对集合

  • Set<Map.Entry<K, V>> entrySet():返回一个包含所有键值对的Set集合,每个元素都是Map.Entry类型的对象。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<String, Integer> myMap =new HashMap<String, Integer>() {{
    put("Apple", 1);
    put("Banana", 2);
    put("Mango", 3);
    put("Orange", 4);
    put("Pear", 5);
}};
// 获取键值对
Set<Map.Entry<String, Integer>> entries = myMap.entrySet();
System.out.println(entries);// 输出: [Apple=1, Pear=5, Mango=3, Orange=4, Banana=2]

Map集合遍历

使用 keySet() 遍历键值对

  • keySet()方法返回一个包含所有键的Set视图,通过迭代这个Set可以获取到所有的键,再通过Map的get()方法取得对应的值。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<Integer, String> myMap =new HashMap<Integer, String>() {{
    put(1, "Apple");
    put(2, "Banana");
    put(3, "Mango");
    put(4, "Orange");
    put(5, "Pear");
}};
// 使用keySet遍历
for (Integer key : myMap.keySet()) {
    String value = myMap.get(key);
    System.out.println("Key: " + key + ", Value: " + value);
}

使用 entrySet() 遍历键值对

  • entrySet()方法返回一个包含所有键值对(Map.Entry对象)的Set视图,可以直接通过Map.Entry对象获取键和值。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<Integer, String> myMap =new HashMap<Integer, String>() {{
    put(1, "Apple");
    put(2, "Banana");
    put(3, "Mango");
    put(4, "Orange");
    put(5, "Pear");
}};
// 使用 entrySet() 遍历键值对
for (Map.Entry<Integer, String> entry : myMap.entrySet()) {
    // 获取 键
    Integer key = entry.getKey();
    // 获取 值
    String value = entry.getValue();
    System.out.println("Key: " + key + ", Value: " + value);
}

使用 forEach()

  • forEach()方法和Stream API是在Java 8中引入的,提供了更加简洁的遍历方式,尤其在处理集合时可以轻松实现链式操作。
java 复制代码
// 创建一个 Map 集合,并在构造函数中直接添加初始键值对
Map<Integer, String> myMap =new HashMap<Integer, String>() {{
    put(1, "Apple");
    put(2, "Banana");
    put(3, "Mango");
    put(4, "Orange");
    put(5, "Pear");
}};
//  使用 forEach() 遍历输出
myMap.forEach((key,value)->System.out.println("Key: " + key + ", Value: " + value));

HashMap 集合

HashMap是基于哈希表实现的Map接口的一个非同步实现类,允许存储键值对(key-value pairs),并且可以高效地根据键来查找值。

  • 数据结构HashMap内部采用数组和链表(或红黑树,自JDK1.8开始)相结合的方式来存储数据。数组用于快速定位,链表或红黑树用于解决哈希冲突。
  • 键的唯一性 :依赖hashCode方法和equals方法保证键的唯一
  • 初始化 :如果键要存储的是自定义对象,需要重写hashCodeequals方法

代码示例

创建一个学生类,键是学生对象(Student):

java 复制代码
import java.util.Objects;

public class Student {
    private String mame;// 姓名
    private int age;// 年龄

    public Student() {
    }

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

    public String getMame() {
        return mame;
    }

    public void setMame(String mame) {
        this.mame = mame;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // 为了保证对象的唯一性,重写equals 和 hashCode
    // 如果学生对象的成员变量值相同,我们就认为是同一个对象
    @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(mame, student.mame);
    }

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

测试类:

java 复制代码
//创建HashMap集合对象
HashMap<Student, String> stu = new HashMap<>();
// 创建学生对象
Student s1 = new Student("李一", 30);
Student s2 = new Student("李一", 30);
Student s3 = new Student("张三", 37);
Student s4 = new Student("李四", 32);

// 把学生添加到集合
stu.put(s1,"北京");
stu.put(s2,"重庆");
stu.put(s3,"上海");
stu.put(s4,"曼哈顿");
// 遍历集合
for (Student key : stu.keySet()) {
    String value = stu.get(key);
    System.out.println(key.getName() + "," + key.getAge() + "," + value);
}

TreeMap集合

TreeMap是Java集合框架中实现Map接口的一个类,它使用红黑树(Red-Black Tree)作为底层数据结构,确保键的有序存储。

  • TreeMap的键值对是有序的,可以按照键的自然顺序(键实现Comparable接口)或者通过自定义Comparator进行排序。
  • 红黑树是一种自平衡二叉查找树,保证了插入、删除和查找操作的时间复杂度在最坏情况下均为O(log n)。

代码示例

创建一个学生类:

java 复制代码
import java.util.Objects;

public class Student implements Comparable<Student> {
    private String name;// 姓名
    private int age;// 年龄

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    // 为了保证对象的唯一性,重写equals 和 hashCode
    // 如果学生对象的成员变量值相同,我们就认为是同一个对象
    @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);
    }

    // 继承 Comparable接口,重写 compareTo方法,实现学生根据条件进行排序
    @Override
    public int compareTo(Student o) {
        //按照年龄进行排序
        int result = o.getAge() - this.getAge();
        //次要条件,按照姓名排序。
        result = result == 0 ? o.getName().compareTo(this.getName()) : result;
        return result;
    }
}

测试方法:

java 复制代码
//创建TreeMap集合对象
TreeMap<Student, String> stu = new TreeMap<>();
// 创建学生对象
Student s1 = new Student("李一", 30);
Student s2 = new Student("李一", 30);
Student s3 = new Student("张三", 37);
Student s4 = new Student("李四", 32);

// 把学生添加到集合
stu.put(s1,"北京");
stu.put(s2,"重庆");
stu.put(s3,"上海");
stu.put(s4,"曼哈顿");
// 遍历集合
for (Student key : stu.keySet()) {
    String value = stu.get(key);
    System.out.println(key.getName() + "," + key.getAge() + "," + value);
}
相关推荐
崔庆才丨静觅11 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
曹牧1 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法2 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7252 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎2 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄2 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea