当前位置:首页 > 技术 > 正文内容

Java集合框架深度解析:Collection与Map体系详解

访客 技术 2026年7月5日 1

集合框架概述

Java集合框架主要分为两大体系:单列集合(Collection)和双列集合(Map)。其中Collection接口是所有单列集合的根接口,而Map则处理键值对数据。

单列集合:Collection接口

单列集合的特点是每次只能操作一个元素。当集合存储自定义对象时,务必重写equals()方法,否则默认比较的是对象引用地址,可能导致元素删除或判断逻辑异常。

Collection通用遍历方式

1. 迭代器遍历

通过Iterator对象依次访问集合元素,支持在遍历过程中安全删除元素。

2. 增强for循环

语法简洁,但底层依然依赖迭代器实现。编译后的字节码文件会还原为迭代器模式。

3. forEach方法

基于函数式编程思想,需传入Consumer接口实现。推荐使用Lambda表达式简化代码:

Collection<String> items = new ArrayList<>();
items.add("Java");
items.add("Python");
items.add("Go");

// 匿名内部类方式
items.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

// Lambda简化写法
items.forEach(s -> System.out.println(s));

List接口详解

List系列集合具有以下特征:元素有序存储、支持索引访问、允许重复元素。

List特有方法

  • add(int index, E element):指定位置插入
  • remove(int index):删除指定索引元素
  • get(int index):获取指定索引元素
  • set(int index, E element):修改指定位置元素

并发修改异常处理

遍历List时直接调用集合的增删方法会引发ConcurrentModificationException。解决方案:

  • 使用迭代器的remove()方法
  • 采用普通for循环手动控制索引
  • 使用并发集合类(如CopyOnWriteArrayList)

ListIterator双向遍历

ListIterator扩展了Iterator功能,支持逆向遍历。使用前必须先正向遍历到末尾:

List<String> data = new ArrayList<>();
data.add("alpha");
data.add("beta");
data.add("gamma");

ListIterator<String> li = data.listIterator();
while (li.hasNext()) {
    System.out.println(li.next());
}

System.out.println("---反向输出---");
while (li.hasPrevious()) {
    System.out.println(li.previous());
}

ArrayList

底层采用动态数组实现,查询效率高(O(1)),增删效率低(需移动元素)。线程不安全,适合单线程环境。

Vector

与ArrayList类似但线程安全(方法使用synchronized修饰)。扩容机制如下:

  • 无参构造:初始容量10,每次扩容为原容量2倍
  • 指定初始容量:扩容倍率同无参构造
  • 指定容量增量:每次增加指定值
// Vector扩容核心逻辑
private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = ArraysSupport.newLength(oldCapacity,
            minCapacity - oldCapacity,
            capacityIncrement > 0 ? capacityIncrement : oldCapacity);
    return elementData = Arrays.copyOf(elementData, newCapacity);
}

Stack

继承Vector,实现后进先出(LIFO)栈结构。提供push、pop、peek、empty、search等标准栈操作。

LinkedList

底层采用双向链表实现,增删效率高(O(1)),查询效率低(O(n))。虽实现List接口支持索引访问,但get(index)方法仍需遍历链表。

Set接口剖析

Set集合保证元素唯一性,无索引,存取顺序不确定(除特定实现外)。

TreeSet

基于红黑树实现,自动对元素排序。支持两种排序机制:

自然排序

元素类实现Comparable接口并重写compareTo方法:

public class Student implements Comparable<Student> {
    private String name;
    private int age;
    
    @Override
    public int compareTo(Student other) {
        // 按年龄升序,年龄相同按姓名排序
        if (this.age != other.age) {
            return this.age - other.age;
        }
        return this.name.compareTo(other.name);
    }
}

比较器排序

创建TreeSet时传入Comparator实现,优先级高于自然排序:

// Lambda方式
TreeSet<Student> sortedSet = new TreeSet<>((s1, s2) -> {
    if (s1.getAge() != s2.getAge()) {
        return s2.getAge() - s1.getAge(); // 按年龄降序
    }
    return s2.getName().compareTo(s1.getName()); // 姓名降序
});

HashSet

基于哈希表实现,依赖HashMap存储数据。保证元素唯一性的关键在于同时重写hashCode()equals()方法:

  • 相同对象必须产生相同的哈希码
  • 哈希码相同时,equals方法需能正确判断内容是否一致

LinkedHashSet

继承HashSet,额外维护双向链表记录插入顺序。兼具HashSet的去重特性和可预测的迭代顺序。

集合使用场景建议

  • 需要快速随机访问:ArrayList
  • 频繁增删操作:LinkedList
  • 需要排序:TreeSet/TreeMap
  • 需要唯一性:HashSet/HashMap
  • 需要保持插入顺序:LinkedHashSet/LinkedHashMap
  • 线程安全:Vector/Collections.synchronizedXxx

Collection工具类

Collections提供sort、binarySearch、shuffle等静态方法操作集合。部分方法支持传入比较器自定义排序规则。

双列集合:Map接口

Map存储键值对,键唯一、值可重复。底层数据结构仅针对键有效。

Map核心方法

  • put(K key, V value):添加/修改键值对
  • remove(Object key):根据键删除
  • get(Object key):根据键获取值
  • containsKey(Object key):检查键是否存在

Map遍历方式

三种经典遍历方法:

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);

// 1. 键找值
for (String name : scores.keySet()) {
    System.out.println(name + ": " + scores.get(name));
}

// 2. 遍历Entry对象
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    System.out.println(entry.getKey() + " - " + entry.getValue());
}

// 3. forEach + Lambda
scores.forEach((k, v) -> System.out.println(k + " = " + v));

Map实现类对比

HashMap

基于哈希表实现,键唯一(需重写hashCode和equals)。允许null键和null值,非线程安全。

TreeMap

红黑树实现,自动对键排序。键类需实现Comparable接口或传入比较器。

LinkedHashMap

继承HashMap,额外维护双向链表确保迭代顺序与插入顺序一致。适合需要可预测遍历顺序的场景。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。