面试基础--Java 集合框架详解

news2025/2/25 6:07:44

Java 集合框架详解:从 ArrayListHashMap 的底层原理

引言

在 Java 开发中,集合框架(Collection Framework)是处理数据存储和操作的核心工具。无论是日常开发还是大厂面试,对集合框架的理解都是考察的重点之一。本文将详细讲解 ArrayListLinkedList 以及 HashMap 的底层实现原理,并通过对比分析它们的优缺点和适用场景。


一、List 接口的实现:ArrayListLinkedList

1. ArrayList 的底层实现

ArrayList 是基于 动态数组 实现的,其内部使用一个 对象数组(Object[]) 来存储数据。当数组空间不足时,ArrayList 会自动扩容。

核心特性
  • 查询效率高:由于数组是连续内存空间,可以通过索引直接访问元素,时间复杂度为 O(1)。
  • 增删效率低:在中间位置插入或删除元素时,需要移动大量数据,时间复杂度为 O(n)。
  • 动态扩容机制:默认情况下,ArrayList 的容量每次增加 50%(即 newCapacity = oldCapacity + (oldCapacity >> 1))。
源码分析
public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final int DEFAULT_CAPACITY = 10;
    transient Object[] elementData; // 存储元素的数组
    private int size; // 当前列表大小

    public E get(int index) {
        rangeCheck(index);
        return (E) elementData[index];
    }

    public void add(E e) {
        if (size == elementData.length)
            expandCapacity();
        elementData[size++] = e;
    }

    private void expandCapacity() {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

2. LinkedList 的底层实现

LinkedList 是基于 双向链表 实现的。每个节点(Node)包含一个指向前后节点的指针以及存储的数据。

核心特性
  • 查询效率低:由于链表是非连续内存空间,需要从头或尾遍历到目标节点,时间复杂度为 O(n)。
  • 增删效率高:在链表中间插入或删除元素时,只需要修改前后节点的指针,时间复杂度为 O(1)。
源码分析
public class LinkedList<E> extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    private static class Node<E> {
        E item; // 存储的元素
        Node<E> next; // 后继节点指针
        Node<E> prev; // 前驱节点指针

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    private transient Node<E> first; // 首节点
    private transient Node<E> last; // 末尾节点

    public void addFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
    }

    public E get(int index) {
        checkElementIndex(index);
        Node<E> node = node(index);
        return node.item;
    }

    private Node<E> node(int index) {
        if (index < (size >> 1)) { // 从前向后查找
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else { // 从后向前查找
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
}

3. ArrayListLinkedList 的对比

特性ArrayListLinkedList
存储结构动态数组双向链表
查询效率高(O(1))低(O(n))
增删效率低(O(n))高(O(1))
内存占用较高(额外存储空间用于扩容)较低(仅存储节点和指针)
适用场景需要频繁查询的场景需要频繁增删的场景

二、Map 接口的实现:HashMap 的底层原理

1. HashMap 的基本结构

HashMap 是基于 哈希表(Hash Table) 实现的,其底层是一个 数组+链表+红黑树 的组合结构。

核心特性
  • 存储结构:数组中的每个元素称为一个“桶”(Bucket),每个桶包含一组键值对。
  • 哈希函数:通过 hashCode() 方法计算键的哈希值,并将其映射到数组索引位置。
  • 解决哈希冲突:当多个键映射到同一个索引时,使用链表或红黑树存储这些键值对。

2. 哈希冲突的处理

(1)拉链法(Chaining)

当发生哈希冲突时,HashMap 使用 拉链法 将多个键值对存储在同一个桶中。具体实现方式如下:

  • 如果一个桶中只有一个节点,则使用单链表结构。
  • 当链表长度超过 8 时,链表会被转换为红黑树(JDK 1.8 及以上版本)。
(2)开放地址法(Open Addressing)

HashMap 不采用开放地址法,而是通过拉链法解决哈希冲突。


3. HashMap 的源码分析

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
    private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始容量 16
    private static final float LOAD_FACTOR = 0.75f; // 负载因子

    transient Node<K,V>[] table; // 存储节点的数组
    private int size; // 当前键值对数量
    int threshold; // 扩容阈值(容量 × 负载因子)

    public V get(Object key) {
        Node<K,V> node = getNode(hash(key), key);
        return (node == null) ? null : node.value;
    }

    private Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab = table;
        int index = (tab.length - 1) & hash; // 计算索引
        for (Node<K,V> e = tab[index]; e != null; e = e.next) {
            if (e.hash == hash && (key == e.key || key.equals(e.key))) {
                return e;
            }
        }
        return null;
    }

    public boolean put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    private int hash(int originalHash) {
        // 高位参与运算,减少碰撞概率
        int h = originalHash ^ (originalHash >>> 16);
        return h;
    }
}

4. HashMap 的扩容机制

当键值对的数量超过 扩容阈值(threshold) 时,HashMap 会执行扩容操作:

  • 新容量为当前容量的 2 倍。
  • 所有键值对会被重新散列到新的数组中。

5. HashMap 的性能分析

特性描述
时间复杂度平均情况下,查询、插入和删除的时间复杂度为 O(1)
空间复杂度O(n),其中 n 是键值对的数量
适用场景需要高效查询的场景

总结

  • ArrayListLinkedList 的选择取决于具体的增删查改需求。
  • HashMap 在现代 Java 中提供了高效的键值存储能力,但需要注意哈希冲突和扩容机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304734.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

轻量级日志管理平台Grafana Loki

文章目录 轻量级日志管理平台Grafana Loki背景什么是Loki为什么使用 Grafana Loki&#xff1f;架构Log Storage Grafana部署使用基于 Docker Compose 安装 LokiMinIO K8s集群部署Loki采集Helm 部署方式和案例 参考 轻量级日志管理平台Grafana Loki 背景 在微服务以及云原生时…

《跟李沐学 AI》AlexNet论文逐段精读学习心得 | PyTorch 深度学习实战

前一篇文章&#xff0c;使用 AlexNet 实现图片分类 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于学习 9年后重读深度学习奠基作之一&#xff1a;AlexNet【下】【论文精读】】的心得。 《跟李沐…

【电机控制器】FU6832S——持续更新

【电机控制器】FU6832S——持续更新 文章目录 [TOC](文章目录) 前言一、ADC二、UART三、PWM四、参考资料总结 前言 使用工具&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、ADC 二、UART 三、PWM 四、参考资料 总结 本文仅仅简…

计算机视觉算法实战——产品分拣(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ 1. 领域简介✨✨ 产品分拣是工业自动化和物流领域的核心技术&#xff0c;旨在通过机器视觉系统对传送带上的物品进行快速识别、定位和分类&a…

基于模块联邦的微前端架构:重构大型前端应用的模块化边界

引言&#xff1a;企业级前端的模块化困境 字节跳动广告系统采用Webpack 5模块联邦后&#xff0c;主应用构建时间从14分钟降至38秒&#xff0c;微应用独立发布频率提升至每天50次。在动态加载机制下&#xff0c;首屏资源加载体积减少79%&#xff0c;跨团队组件复用率达到92%。其…

Android之图片保存相册及分享图片

文章目录 前言一、效果图二、实现步骤1.引入依赖库2.二维码生成3.布局转图片保存或者分享 总结 前言 其实现在很多分享都是我们自定义的&#xff0c;更多的是在界面加了很多东西&#xff0c;然后把整个界面转成图片保存相册和分享&#xff0c;而且现在分享都不需要第三方&…

Linux放行端口

8080这个端口测试看telnet是不通的&#xff0c;您服务器内是否有对应的业务监听了这个端口呢&#xff1f;您到服务器内执行下&#xff1a; netstat -nltp |grep 8080 同时服务器内执行下&#xff1a; systemctl status firewalld iptables -nL 截图反馈下&#xff0c;我看下防火…

Spring Boot延迟执行实现

说明&#xff1a;本文介绍如何在Spring Boot项目中&#xff0c;延迟执行某方法&#xff0c;及讨论延迟执行方法的是事务问题。 搭建Demo 首先&#xff0c;创建一个Spring Boot项目&#xff0c;pom.xml如下&#xff1a; <?xml version"1.0" encoding"UTF-…

npm i 失败权限问题

安装完node之后, 测试全局安装一个最常用的 express 模块进行测试 失败&#xff0c;但是用管理员权限打开cmd 安装就成功。 报错如下&#xff1a; npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and …

uniapp 微信小程序打包之后vendor.js 主包体积太大,解决办法,“subPackages“:true设置不生效

现在是打包的时候&#xff0c;vendor.js 的内容全部打到了主包里面&#xff0c; 说一下我的方法&#xff1a; 1. 通过发行 小程序打包 这样打包的体积是最小的&#xff0c;打包之后打开微信开发工具&#xff0c;然后再上传 2.manifest.json,在“mp-weixin”里添加代码 "…

23.2、云计算安全机制与案例分析

目录 云计算安全保护机制与技术方案云计算安全保护机制与技术方案常见云计算网络安全机制云计算安全管理与运维云计算安全综合应用案例分析 - 阿里云云计算安全综合应用案例分析 - 腾讯云云计算安全综合应用案例分析 - 华为云 云计算安全保护机制与技术方案 首先针对云计算&am…

游戏引擎学习第120天

仓库:https://gitee.com/mrxiao_com/2d_game_3 上次回顾&#xff1a;周期计数代码 我们正在进行一个项目的代码优化工作&#xff0c;目标是提高性能。当前正在优化某个特定的代码片段&#xff0c;已经将其执行周期减少到48个周期。为了实现这一目标&#xff0c;我们设计了一个…

将DeepSeek接入vscode的N种方法

接入deepseek方法一:cline 步骤1:安装 Visual Studio Code 后,左侧导航栏上点击扩展。 步骤2:搜索 cline,找到插件后点击安装。 步骤3:在大模型下拉菜单中找到deep seek,然后下面的输入框输入你在deepseek申请的api key,就可以用了 让deepseek给我写了一首关于天气的…

AI智算-k8s+SGLang实战:DeepSeek-r1:671b满血版多机多卡私有化部署全攻略

k8sSGLang实战&#xff1a;DeepSeek-r1:671b满血版多机多卡私有化部署全攻略 前言环境准备1. 模型下载2.软硬件环境介绍 正式部署1. 部署LWS API2. 通过 LWS 部署DeepSeek-r1模型3. 查看显存占用情况4. 服务对外暴露5. 测试部署效果5.1 通过 curl5.2 通过 OpenWebUIa. 部署 Ope…

【蓝桥杯单片机】第十三届省赛第二场

一、真题 二、模块构建 1.编写初始化函数(init.c) void Cls_Peripheral(void); 关闭led led对应的锁存器由Y4C控制关闭蜂鸣器和继电器 2.编写LED函数&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 将ucLed取反的值赋给P0 开启锁存器 关闭锁存…

从零开始玩转TensorFlow:小明的机器学习故事 5

图像识别的挑战 1 故事引入&#xff1a;小明的“图像识别”大赛 小明从学校里听说了一个有趣的比赛&#xff1a;“美食图像识别”。参赛者需要训练计算机&#xff0c;看一张食物照片&#xff08;例如披萨、苹果、汉堡等&#xff09;&#xff0c;就能猜出这是什么食物。听起来…

sql的索引与性能优化相关

之前面试的时候&#xff0c;由于在简历上提到优化sql代码&#xff0c;老是会被问到sql索引和性能优化问题&#xff0c;用这个帖子学习记录一下。 1.为什么要用索引 ------------------------------------------------------------------------------------------------------…

碰撞检测 | 图解凸多边形分离轴定理(附ROS C++可视化)

目录 0 专栏介绍1 凸多边形碰撞检测2 多边形判凸算法3 分离轴定理(SAT)4 算法仿真与可视化4.1 核心算法4.2 仿真实验 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xff1a;曲线…

计算机网络真题练习(高软29)

系列文章目录 计算机网络阶段练习 文章目录 系列文章目录前言一、真题练习总结 前言 计算机网络的阶段练习题&#xff0c;带解析答案。 一、真题练习 总结 就是高软笔记&#xff0c;大佬请略过&#xff01;

DPVS-1:编译安装DPVS (ubuntu22.04)

操作系统 rootubuntu22:~# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy rootubuntu22:~# 前置软件准备 apt install git apt install meson apt install gcc ap…