Java中常用的数据结构有哪些以及如何选择最合适的?

来源:图像处理网作者:北京SEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《Java中常用的数据结构有哪些以及如何选择最合适的?》,敬请观看详情。ArrayList和LinkedList在随机访问时性能差距能达到百倍级别,根源在于前者基于数组实现而后者依赖节点指针跳转。Java集合框架提供的数据结构远不止这两种,HashMap利用哈希表在常数时间完成查找,TreeMap则通过红黑树维持键的有序性。若处理多线程共享数据,ConcurrentHashMap采用分段锁降低竞争。理解每种结构背后的存储方式与操作开销,才能在实际业务里避开误用导致的性能陡降。本文从底层实现切入,对比典型结构的适用边界与编码注意点。

在Java开发里,数据结构的选择往往直接决定了程序的运行效率和可维护性。JDK自带的集合框架已经覆盖了绝大多数业务场景,但从ArrayList到ConcurrentHashMap,它们的内部机制和适用条件差别很大。如果只凭习惯随便选,很容易在大数据量或高并发时出现性能问题。

Java中常用的数据结构有哪些以及如何选择最合适的?

一、线性表结构:ArrayList与LinkedList

ArrayList是基于动态数组实现的线性表,在内存中占用连续空间。这种结构让它能通过下标在常数时间访问任意元素,但在中间位置插入或删除时,需要移动后续所有元素,开销随数据量线性增长。当数组容量不足时,ArrayList会创建一个更大的数组并拷贝原有数据,因此预先通过构造函数指定容量能减少扩容带来的损耗。

LinkedList采用双向链表存储,每个节点包含前驱和后继指针。它在头部或尾部增删元素非常高效,只需要修改相邻节点的引用,但随机访问必须从链表头或尾遍历到目标位置,时间复杂度为O(n)。下面的代码展示了两者在遍历方式上的差异:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<Integer> arrayList = new ArrayList<>();
        List<Integer> linkedList = new LinkedList<>();

        // ArrayList随机访问高效
        for (int i = 0; i < 100000; i++) {
            arrayList.add(i);
        }
        int val = arrayList.get(50000); // 直接定位

        // LinkedList随机访问低效
        for (int i = 0; i < 100000; i++) {
            linkedList.add(i);
        }
        int slowVal = linkedList.get(50000); // 需要遍历
    }
}

从实践角度看,除非频繁在表头做插入删除,否则应优先使用ArrayList。LinkedList除了遍历慢,还会因为节点对象额外存储指针而增加内存占用。在JDK 8之后,即便使用增强for循环,LinkedList的迭代器仍然要逐个跳转节点,无法像数组那样利用CPU缓存预取。

二、映射结构:HashMap与TreeMap

HashMap是最常用的键值对结构,底层在JDK 8中由数组加链表加红黑树组成。它通过键的hashCode计算桶位置,理想情况下增删查改都能接近O(1)。当多个键哈希冲突且链表长度超过8时,链表会转为红黑树,将最坏情况的时间复杂度从O(n)降到O(log n)。需要注意的是,作为键的对象必须正确重写hashCode和equals方法,否则会出现逻辑上相等的键被当成不同键处理。

TreeMap基于红黑树实现,会自动按照键的自然顺序或指定的比较器排序。它适合需要范围查询或按顺序遍历键的场景,但每次插入和删除都要维持树的平衡,单步操作成本为O(log n)。下面示例展示两者排序行为的不同:

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class MapDemo {
    public static void main(String[] args) {
        Map<String, Integer> hashMap = new HashMap<>();
        hashMap.put("banana", 3);
        hashMap.put("apple", 1);
        hashMap.put("pear", 2);
        System.out.println(hashMap); // 顺序不确定

        Map<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("banana", 3);
        treeMap.put("apple", 1);
        treeMap.put("pear", 2);
        System.out.println(treeMap); // 按字母顺序输出
    }
}

在选择时,如果只关心快速查找而不要求顺序,HashMap是默认选项。当业务需要获取最小键、最大键或进行区间统计,比如计算某时间段内的订单,TreeMap会更合适。另外HashMap允许一个null键,TreeMap若使用自然排序则不支持null键,否则会抛出空指针异常。

三、线程安全场景下的数据结构

在多线程环境中,普通的HashMap或ArrayList都可能因并发修改产生数据不一致甚至死循环。虽然可以用Collections.synchronizedMap包装,但那种方式会对整个容器加锁,并发度很低。JDK并发包提供的ConcurrentHashMap采用更细粒度的控制,在JDK 8里利用CAS和 synchronized 锁定单个桶头节点,读操作大多无锁,因此吞吐量明显更高。

对于单纯的生产者消费者模型,还可以使用ArrayBlockingQueue或LinkedBlockingQueue等阻塞队列,它们内部已经处理好等待与唤醒逻辑。下面的代码演示了ConcurrentHashMap的基本线程安全用法:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentDemo {
    public static void main(String[] args) throws InterruptedException {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        Runnable task = () -> {
            for (int i = 0; i < 100; i++) {
                map.merge("count", 1, Integer::sum);
            }
        };
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(map.get("count")); // 输出200
    }
}

需要强调的是,ConcurrentHashMap只能保证单个操作的原子性,像先判断存在再插入这种复合操作仍需使用merge或computeIfAbsent等提供的方法。如果业务要求跨多个键的事务一致性,就要考虑引入外部锁或使用数据库事务,而非依赖集合本身。

四、如何根据业务做选型

选型的核心是先明确操作特征:读多写少且需要随机访问,选ArrayList;写多读少且频繁在两端操作,考虑LinkedList或ArrayDeque;键值查找且无序,HashMap最合适;需要排序或范围扫描,用TreeMap;高并发共享数据,优先ConcurrentHashMap或并发队列。同时应关注数据规模,小数据量下不同结构差异不明显,但达到十万或百万级时,时间复杂度带来的差距会被放大数十倍。

此外,编码时应面向List、Map等接口编程,而非具体实现类,这样后续更换结构只需改动实例化处。比如将List<String> list = new ArrayList<>()改为LinkedList,调用方代码无需调整。合理利用JDK提供的数据结构,既能减少重复造轮子,也能借助成熟实现规避大量边界错误。

Java数据结构集合框架时间复杂度修改时间:2026-08-02 14:21:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。