java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java集合框架set map

Java集合框架Set&Map详细解析

作者:sjandhyc

这篇文章介绍了Java集合框架中的Map和Set接口,Map接口用于存储键值对,常用实现类有HashMap、LinkedHashMap和TreeMap,Set接口用于存储唯一元素,常用实现类有HashSet、LinkedHashSet和TreeSet,每种实现类都有其特点和适用场景,感兴趣的朋友跟随小编一起看看吧

第一章 Map集合

Map 是 Java 集合框架中用于存储键值对(Key-Value) 的接口,它允许通过键(Key)快速查找对应的值(Value),属于非线性集合。与 Collection 接口(存储单元素)不同,Map 存储的是 “键值对映射关系”,键具有唯一性(不允许重复),而值可以重复。

1.1 常见的Map集合

HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

TreeMap<K,V>:TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序。

1.2 Map的常用方法

Map接口中定义了很多方法,常用的如下:

1.3 Map的遍历方法

一、遍历所有键(keySet())

通过 keySet() 方法获取所有键的 Set 集合,再通过键获取对应的值。

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTraversal {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("苹果", 5);
        map.put("香蕉", 3);
        map.put("橙子", 7);
        // 1. 遍历所有键,再通过键获取值
        Set<String> keys = map.keySet(); // 获取键的集合
        for (String key : keys) {
            Integer value = map.get(key); // 通过键获取值
            System.out.println(key + " → " + value);
        }
    }
}

二、遍历所有键值对(entrySet())

通过 entrySet() 方法获取所有键值对的 Set 集合,直接从键值对对象中获取键和值。

// 2. 遍历所有键值对(推荐,效率最高)
Set<Map.Entry<String, Integer>> entries = map.entrySet(); // 获取键值对集合
for (Map.Entry<String, Integer> entry : entries) {
    String key = entry.getKey(); // 获取键
    Integer value = entry.getValue(); // 获取值
    System.out.println(key + " → " + value);
}

三、遍历所有值(values())

// 3. 仅遍历值(无法获取对应键)
for (Integer value : map.values()) {
    System.out.println("值:" + value);
}

四、迭代器(Iterator)遍历

通过迭代器遍历 keySet() 或 entrySet(),支持在遍历中安全删除元素。

import java.util.Iterator;
// 4. 迭代器遍历 entrySet(支持遍历中删除)
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, Integer> entry = iterator.next();
    System.out.println(entry.getKey() + " → " + entry.getValue());
    // 遍历中删除元素(必须用迭代器的 remove() 方法,否则抛异常)
    if (entry.getValue() < 5) {
        iterator.remove(); 
    }
}

1.4 HashMap的使用

HashMap 是 Java 集合框架中基于哈希表实现的 Map 接口实现类,用于存储键值对(Key-Value),其特点为:

1.可以存放键值对

2.键不允许重复存放,依据是添加进来的元素的键 hashCode()和 equals()

3.存取顺序不一致

4.允许存放null键、null值(键最多只能有一个 null

5.线程不安全

6.JDK1.8 HashMap 采用 “数组 + 链表 + 红黑树” 的混合结构,平衡效率与哈希冲突问题

在使用上可以参考下面的代码:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapUsage {
    public static void main(String[] args) {
        // 1. 初始化(指定初始容量可减少扩容次数)
        Map<String, Integer> scoreMap = new HashMap<>(16); // 初始容量16
        // 2. 添加键值对
        scoreMap.put("张三", 90);
        scoreMap.put("李四", 85);
        scoreMap.put("王五", 95);
        scoreMap.put("张三", 92); // 键重复,覆盖旧值(张三的分数变为92)
        // 3. 获取值
        int lisiScore = scoreMap.get("李四"); // 85
        System.out.println("李四的分数:" + lisiScore);
        // 4. 判断是否包含键/值
        boolean hasWangwu = scoreMap.containsKey("王五"); // true
        boolean hasScore90 = scoreMap.containsValue(90); // false(已被覆盖)
        // 5. 遍历(推荐 entrySet() 方式,效率最高)
        Set<Map.Entry<String, Integer>> entries = scoreMap.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        // 6. 删除元素
        scoreMap.remove("王五"); // 删除王五的键值对
        // 7. 其他操作
        System.out.println("元素数量:" + scoreMap.size()); // 2(张三、李四)
        scoreMap.clear(); // 清空所有元素
        System.out.println("是否为空:" + scoreMap.isEmpty()); // true
    }
}

注意:

作为键的对象(如自定义类)必须重写 hashCode() 和 equals() 方法,否则会导致:

hashCode() 未重写:不同对象可能计算出相同哈希值(哈希冲突加剧),或相同对象计算出不同哈希值(无法正确查找)。

equals() 未重写:哈希值相同的不同对象无法被识别为不同键(导致误判为重复键)。

1.5 LinkedHashMap的使用

LinkedHashMap 是 HashMap 的子类,它在哈希表的基础上,通过双向链表维护了键值对的插入顺序或访问顺序,兼具哈希表的高效查找能力和链表的有序性。

1.可以存放键值对

2.键不允许重复存放,依据是添加进来的元素的键 hashcode()和equals()

3.可以保证存取顺序一致性,由于多了一条链表可以维系存进来的顺序

4.允许存放null键、null值

5.线程不安全

LinkedHashMap 在 HashMap 的基础上,给每个节点(Entry)增加了两个指针:before(前一个节点)和 after(后一个节点),形成双向链表:

参考代码如下,比起HashMap保证了存取的一致性:

import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo {
    public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("name", "张三");
        map.put("age", "20");
        map.put("gender", "男");
        // 遍历顺序与插入顺序一致
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        // 输出:
        // name:张三
        // age:20
        // gender:男
    }
}

LinkedHashMap 是 “有序版的 HashMap”,在保留哈希表高效操作的同时,通过双向链表实现了顺序维护。

1.6TreeMap的使用

TreeMap 是 Java 集合框架中基于红黑树(Red-Black Tree) 实现的 Map 接口实现类,其核心特性是按键(Key)的自然顺序或自定义顺序进行排序,适合需要有序键值对的场景。

1.可以存放键值对

2.键不允许重复存放,依据是添加进来的元素的键 compareTo()返回0

3.存取顺序不一致,但是会对键进行排序

3.1 要么元素自身具备比较性,implements Comparable, 重写compareTo()

3.2 要么集合容器自身具备比较性,在构造方法中,传入Comparator比较器,重写compare()

4.不允许存放null键,可以存放null值

5.线程不安全

如通过自然顺序比较则代码如下;

import java.util.TreeMap;
import java.util.Map;
public class TreeMapNaturalOrder {
    public static void main(String[] args) {
        // 键为 Integer(已实现 Comparable,默认按数字升序排序)
        TreeMap<Integer, String> numMap = new TreeMap<>();
        numMap.put(3, "Three");
        numMap.put(1, "One");
        numMap.put(2, "Two");
        numMap.put(5, "Five");
        numMap.put(4, "Four");
        System.out.println("按数字升序排序:");
        for (Map.Entry<Integer, String> entry : numMap.entrySet()) {
            System.out.println(entry.getKey() + " → " + entry.getValue());
        }
        // 键为 String(已实现 Comparable,默认按字典序排序)
        TreeMap<String, Integer> strMap = new TreeMap<>();
        strMap.put("banana", 3);
        strMap.put("apple", 5);
        strMap.put("orange", 2);
        System.out.println("\n按字符串字典序排序:");
        for (Map.Entry<String, Integer> entry : strMap.entrySet()) {
            System.out.println(entry.getKey() + " → " + entry.getValue());
        }
    }
}

当需要自定义排序规则(如降序、按字段排序等),可通过 Comparator 实现。

import java.util.TreeMap;
import java.util.Comparator;
import java.util.Map;
// 自定义类:Person(包含姓名和年龄)
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() { return age; }
    public String getName() { return name; }
    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}
public class TreeMapCustomOrder {
    public static void main(String[] args) {
        // 自定义比较器:按 Person 的年龄降序排序
        Comparator<Person> ageDescComparator = (p1, p2) -> 
            Integer.compare(p2.getAge(), p1.getAge()); // 降序(p2 - p1)
        // 创建 TreeMap 时传入自定义比较器
        TreeMap<Person, String> map = new TreeMap<>(ageDescComparator);
        map.put(new Person("张三", 20), "学生");
        map.put(new Person("李四", 30), "老师");
        map.put(new Person("王五", 25), "工程师");
        System.out.println("按年龄降序排序:");
        for (Map.Entry<Person, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " → " + entry.getValue());
        }
    }
}

TreeMap 的核心价值在于按键排序和高效的范围操作,其红黑树结构保证了有序性和稳定的性能。使用时需确保键可比较(通过 Comparable 或 Comparator),并注意其不支持 null 键和非线程安全的特性。

第二章 Set接口

java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口都会以某种规则保证存入的元素不出现重复。

Set集合有多个子类,这里我们介绍其中的java.util.HashSetjava.util.LinkedHashSet

其实对于Set 集合本质上可以理解为 Map 中 “键(Key)的集合

2.1 HashSet集合

HashSet 是 Java 集合框架中基于 HashMap 实现的 Set 接口实现类,其核心特性是存储唯一元素(不允许重复) 且不保证元素顺序,是日常开发中最常用的 Set 实现类之一。

使用示例:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetDemo {
    public static void main(String[] args) {
        // 创建 HashSet 实例
        Set<String> set = new HashSet<>();
        // 1. 添加元素(重复元素不会被添加)
        set.add("apple");
        set.add("banana");
        set.add("apple"); // 重复元素,添加失败
        set.add(null);    // 允许添加一个null
        set.add(null);    // 重复null,添加失败
        // 2. 遍历元素(顺序不固定)
        System.out.println("增强for遍历:");
        for (String s : set) {
            System.out.println(s);
        }
        System.out.println("\n迭代器遍历:");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        // 3. 其他常用操作
        System.out.println("\n是否包含banana:" + set.contains("banana")); // true
        System.out.println("元素数量:" + set.size()); // 3(apple、banana、null)
        set.remove("banana"); // 删除元素
        System.out.println("删除后元素:" + set); // [null, apple](顺序可能不同)
        set.clear(); // 清空集合
        System.out.println("清空后是否为空:" + set.isEmpty()); // true
    }
}

当自定义类作为 HashSet 元素时,必须同时重写 hashCode() 和 equals() 方法,否则会导致重复元素无法被识别。

2.2 LinkedHashSet集合

LinkedHashSet 是 HashSet 的子类,底层基于 LinkedHashMap 实现,它在保证元素唯一性的同时,还能维护元素的插入顺序,兼具 HashSet 的高效性和链表的有序性。

使用示例:

import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>();
        // 添加元素(重复元素不生效)
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三"); // 重复,不添加
        // 遍历顺序与插入顺序一致
        System.out.println("遍历元素:");
        for (String name : set) {
            System.out.println(name);
        }
        // 其他操作(与 HashSet 一致)
        System.out.println("\n是否包含李四:" + set.contains("李四")); // true
        set.remove("王五");
        System.out.println("删除后元素:" + set); // [张三, 李四]
    }
}

2.3 TreeSet集合

TreeSet 是 Java 集合框架中基于 TreeMap 实现的 Set 接口实现类,其核心特性是元素唯一且有序,排序规则基于元素的自然顺序或自定义比较器,适合需要对元素进行排序和去重的场景。

1. 自然排序

元素类型需实现 java.lang.Comparable 接口,并重写 compareTo() 方法定义排序规则(如 IntegerString 等内置类已实现)。

import java.util.TreeSet;
import java.util.Set;
public class TreeSetNaturalSort {
    public static void main(String[] args) {
        // 元素为 Integer(已实现 Comparable,默认按数字升序)
        Set<Integer> set = new TreeSet<>();
        set.add(3);
        set.add(1);
        set.add(2);
        set.add(3); // 重复元素,不添加
        System.out.println("自然排序(升序):" + set); // [1, 2, 3]
    }
}
2. 自定义排序

创建 TreeSet 时传入 java.util.Comparator 接口实现类,指定自定义排序规则(如降序、按对象字段排序)。

import java.util.TreeSet;
import java.util.Comparator;
public class TreeSetCustomSort {
    public static void main(String[] args) {
        // 自定义比较器:按整数降序
        Comparator<Integer> descComparator = Comparator.reverseOrder();
        TreeSet<Integer> set = new TreeSet<>(descComparator);
        set.add(3);
        set.add(1);
        set.add(2);
        System.out.println("自定义排序(降序):" + set); // [3, 2, 1]
    }
}

到此这篇关于Java集合框架Set&amp;Map的文章就介绍到这了,更多相关java集合框架set map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文