初识数据结构——Java集合框架解析:List与ArrayList的完美结合

📚 Java集合框架解析:List与ArrayList的完美结合

🌟 前言:为什么我们需要List和ArrayList?

在日常开发中,我们经常需要处理一组数据。想象一下,如果你要管理一个班级的学生名单,或者处理电商网站的商品列表,你会怎么做?Java集合框架中的List和ArrayList就是为解决这类问题而生的利器!

本文将带你深入探索List接口和ArrayList实现类的奥秘,通过丰富的示例和直观的图示,让你彻底掌握它们的用法和原理。


🧩 第一部分:List接口全景图

1. 什么是List?

List是Java集合框架中的一个接口,它继承自Collection接口,代表一个有序的、可重复的元素序列。

public interface List<E> extends Collection<E> {// 一系列方法定义
}
🎯 List的核心特性:
  • 有序性:元素按照插入顺序排列
  • 可重复:允许存储相同的元素
  • 索引访问:可以通过下标直接访问元素

2. List的继承体系(思维导图)

Iterable
Collection
List
ArrayList
LinkedList
Vector

3. List常用方法速查表

方法签名功能描述时间复杂度
boolean add(E e)尾部添加元素O(1)
void add(int index, E element)指定位置插入O(n)
E get(int index)获取指定位置元素O(1)
E set(int index, E element)修改指定位置元素O(1)
E remove(int index)删除指定位置元素O(n)
int size()返回元素个数O(1)
boolean contains(Object o)判断是否包含元素O(n)

🚀 第二部分:ArrayList深度剖析

1. ArrayList的底层原理

ArrayList是基于动态数组实现的顺序表,它自动处理扩容问题,让我们可以专注于业务逻辑。

// 底层核心数组
transient Object[] elementData;
// 实际元素数量
private int size;

2. ArrayList的构造方法对比

构造方法说明初始容量
ArrayList()无参构造10
ArrayList(int initialCapacity)指定初始容量自定义
ArrayList(Collection<? extends E> c)从集合构造集合大小

3. 动态扩容机制揭秘(流程图)

添加元素
容量是否足够?
直接添加
计算新容量
创建新数组
拷贝数据
添加新元素

扩容规则

  • 首次添加元素时扩容到10
  • 后续按1.5倍增长(int newCapacity = oldCapacity + (oldCapacity >> 1)

4. ArrayList的三种遍历方式

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));// 1. for循环+下标
for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
}// 2. 增强for循环
for (String s : list) {System.out.println(s);
}// 3. 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {System.out.println(it.next());
}

实战应用:扑克牌游戏

🃏1. 扑克牌游戏:买牌、洗牌、发牌完整实现

// 定义一个Card类来表示一张扑克牌
public class Card {// 定义一个整数类型的变量rank,用于表示牌的面值public int rank; // 定义一个字符串类型的变量suit,用于表示牌的花色public String suit; // 重写toString方法,用于将Card对象以特定格式输出@Overridepublic String toString() {// 格式化输出牌的花色和面值return String.format("[%s %d]", suit, rank); }
}// 导入List接口,用于存储和操作元素列表
import java.util.List; 
// 导入ArrayList类,用于创建动态数组
import java.util.ArrayList; 
// 导入Random类,用于生成随机数
import java.util.Random; // 定义一个CardDemo类,用于演示扑克牌的操作
public class CardDemo {// 定义一个字符串数组SUITS,包含四种花色public static final String[] SUITS = {"♠", "♥", "♣", "♦"}; // 定义一个静态方法buyDeck,用于创建一副完整的扑克牌private static List<Card> buyDeck() {// 创建一个容量为52的ArrayList对象,用于存储扑克牌List<Card> deck = new ArrayList<>(52); // 外层循环遍历四种花色for (int i = 0; i < 4; i++) { // 内层循环遍历1到13的牌面值for (int j = 1; j <= 13; j++) { // 获取当前花色String suit = SUITS[i]; // 获取当前牌面值int rank = j; // 创建一个Card对象Card card = new Card(); // 设置Card对象的牌面值card.rank = rank; // 设置Card对象的花色card.suit = suit; // 将Card对象添加到deck列表中deck.add(card); }}// 返回包含所有扑克牌的列表return deck; }// 定义一个静态方法swap,用于交换列表中两个位置的元素private static void swap(List<Card> deck, int i, int j) {// 获取索引i位置的Card对象Card t = deck.get(i); // 将索引j位置的Card对象赋值给索引i位置deck.set(i, deck.get(j)); // 将临时变量t(原索引i位置的Card对象)赋值给索引j位置deck.set(j, t); }// 定义一个静态方法shuffle,用于洗牌private static void shuffle(List<Card> deck) {// 创建一个Random对象,使用固定的种子值,保证每次运行结果一致Random random = new Random(20190905); // 从列表的最后一个元素开始向前遍历for (int i = deck.size() - 1; i > 0; i--) { // 生成一个0到i之间的随机整数int r = random.nextInt(i); // 调用swap方法交换索引i和r位置的元素swap(deck, i, r); }}// 程序的入口点public static void main(String[] args) {// 调用buyDeck方法创建一副扑克牌List<Card> deck = buyDeck(); // 打印提示信息,表示刚买回来的牌System.out.println("刚买回来的牌:"); // 打印刚买回来的扑克牌列表System.out.println(deck); // 调用shuffle方法对扑克牌进行洗牌shuffle(deck); // 打印提示信息,表示洗过的牌System.out.println("洗过的牌:"); // 打印洗过的扑克牌列表System.out.println(deck); // 创建一个二维列表hands,用于存储三个玩家的手牌List<List<Card>> hands = new ArrayList<>(); // 为每个玩家创建一个空的手牌列表,并添加到hands中hands.add(new ArrayList<>()); hands.add(new ArrayList<>()); hands.add(new ArrayList<>()); // 模拟每个玩家轮流抓5张牌的过程for (int i = 0; i < 5; i++) { // 遍历三个玩家for (int j = 0; j < 3; j++) { // 从deck列表中移除第一张牌,并添加到当前玩家的手牌列表中hands.get(j).add(deck.remove(0)); }}// 打印提示信息,表示剩余的牌System.out.println("剩余的牌:"); // 打印剩余的扑克牌列表System.out.println(deck); // 打印提示信息,表示A玩家手中的牌System.out.println("A手中的牌:"); // 打印A玩家的手牌列表System.out.println(hands.get(0)); // 打印提示信息,表示B玩家手中的牌System.out.println("B手中的牌:"); // 打印B玩家的手牌列表System.out.println(hands.get(1)); // 打印提示信息,表示C玩家手中的牌System.out.println("C手中的牌:"); // 打印C玩家的手牌列表System.out.println(hands.get(2)); }
}

🔺2. 杨辉三角生成器(leetcode118)

在这里插入图片描述

public List<List<Integer>> generate(int numRows) {List<List<Integer>> triangle = new ArrayList<>();for (int i = 0; i < numRows; i++) {List<Integer> row = new ArrayList<>();for (int j = 0; j <= i; j++) {if (j == 0 || j == i) {row.add(1);} else {row.add(triangle.get(i-1).get(j-1) + triangle.get(i-1).get(j));}}triangle.add(row);}return triangle;}

💡 性能优化与思考

ArrayList的优缺点分析

优点

  • 随机访问速度快(O(1))
  • 内存连续,缓存友好
  • 尾部操作高效

缺点

  • 中间插入/删除效率低(O(n))
  • 扩容有性能开销
  • 可能造成内存浪费

替代方案考虑

场景推荐结构原因
频繁随机访问ArrayListO(1)访问
频繁插入删除LinkedListO(1)插入删除
多线程环境CopyOnWriteArrayList线程安全
固定大小Arrays.asList()不可变

📌 总结与面试必备

  1. List vs ArrayList:List是接口,ArrayList是实现
  2. 扩容机制:初始10,1.5倍增长
  3. 时间复杂度
    • 访问:O(1)
    • 搜索:O(n)
    • 插入/删除:平均O(n)
  4. 线程安全:ArrayList非线程安全,多线程需同步
45% 30% 15% 10% ArrayList使用场景 随机访问 尾部操作 中间操作 其他

🎁 彩蛋:ArrayList的趣味事实

你知道吗?ArrayList在JDK1.2中引入,它的设计受到了C++ STL中vector的启发。但在Java中,为了避免与数学向量概念混淆,才命名为ArrayList!


希望这篇深度解析能帮助你彻底掌握List和ArrayList!如果有任何问题,欢迎在评论区留言讨论。别忘了点赞收藏哦~ 💖

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

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

相关文章

ReFormX:现代化的 React 表单解决方案 - 深度解析与最佳实践

ReFormX文档 表单开发一直是前端工作中最繁琐却又最常见的任务之一。从简单的登录表单到复杂的多步骤配置页面&#xff0c;开发者往往需要编写大量重复代码&#xff0c;处理繁琐的状态管理、数据验证和联动逻辑。ReFormX 应运而生&#xff0c;它不仅是一个表单组件库&#xff…

WinForm真入门(9)——RichTextBox控件详解

WinForm中RichTextBox控件详解&#xff1a;从基础到高级应用 上一文中笔者重点介绍了TextBox控件的详细用法&#xff0c;忘记的 请点击WinForm真入门(8)——TextBox控件详解&#xff0c;那么本文中的RichTextBox与TextBox有什么区别吗&#xff0c;光看名字的话&#xff0c;多了…

Draw.io 全面解析与竞品分析:图表绘制工具的深度对比

目录 一、Draw.io 全面介绍 1. 产品概述 2. 核心功能特点 3. 用户体验 4. 商业模式 二、市场竞品分析 1. 主要竞品概览 2. 深度功能对比 3. 价格策略对比 4. 技术架构对比 三、用户场景与选择建议 1. 不同场景下的工具推荐 2. 未来发展趋势 四、结论 diagrams.net…

kafka分区策略详解

Kafka 分区策略详解 Kafka 的分区策略决定了消息在生产者端如何分配到不同分区&#xff0c;以及在消费者端如何动态分配分区以实现负载均衡。以下是 Kafka 核心分区策略及其适用场景的详细解析&#xff1a; 1、生产者分区策略 生产者负责将消息发送到 Topic 的特定分区&#…

C++ STL 详解 ——list 的深度解析与实践指南

在 C 的标准模板库&#xff08;STL&#xff09;中&#xff0c;list作为一种重要的序列式容器&#xff0c;以其独特的双向链表结构和丰富的操作功能&#xff0c;在许多编程场景下发挥着关键作用。深入理解list的特性与使用方法&#xff0c;能帮助开发者编写出更高效、灵活的代码…

GenerationMixin概述

类 类名简单说明GenerateDecoderOnlyOutput继承自 ModelOutput&#xff0c;适用于非束搜索方法的解码器-only模型输出类。GenerateEncoderDecoderOutput继承自 ModelOutput&#xff0c;适用于非束搜索方法的编码器-解码器模型输出类。GenerateBeamDecoderOnlyOutput继承自 Mod…

【备赛】蓝桥杯嵌入式实现led闪烁

原理 由于蓝桥杯的板子带有锁存器&#xff0c;并且与lcd屏幕有冲突&#xff0c;所以这个就成了考点。 主要就是用定时器来实现&#xff0c;同时也要兼顾lcd的冲突。 一、处理LCD函数 首先来解决与lcd屏幕冲突的问题&#xff0c;把我们所有用到的lcd函数改装一下。 以下是基…

C++ 并发性能优化实战:提升多线程应用的效率与稳定性

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;获得2024年博客之星荣誉证书&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发技术&#xff0c…

Python----计算机视觉处理(Opencv:道路检测之车道线拟合)

完整版&#xff1a; Python----计算机视觉处理&#xff08;Opencv:道路检测完整版&#xff1a;透视变换&#xff0c;提取车道线&#xff0c;车道线拟合&#xff0c;车道线显示&#xff09; 一、获取左右车道线的原始位置 导入模块 import cv2 import numpy as np from matplot…

优选算法的妙思之流:分治——归并专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、归并排序 二、例题讲解 2.1. 排序数组 2.2. 交易逆序对的总数 2.3. 计算右侧小于当前元素的个数 2.4. 翻转对 一、归并排序 归并排序也是采用了分治的思想&#xff0c;将数组划分为多个长度为1的子…

C语言查漏补缺:基础篇

1.原理 C语言是一门编译型计算机语言&#xff0c;要编写C代码&#xff0c;C源代码文本文件本身无法直接执行&#xff0c;必须通过编译器翻译和链接器的链接&#xff0c;生成二进制的可执行文件&#xff0c;然后才能执行。这里的二进制的可执行文件就是我们最终要形成的可执行程…

TPS入门DAY02 服务器篇

1.创建空白插件 2.导入在线子系统以及在线steam子系统库 MultiplayerSessions.uplugin MultiplayerSessions.Build.cs 3.创建游戏实例以及初始化会话创建流程 创建会话需要的函数&#xff0c;委托&#xff0c;委托绑定的回调&#xff0c;在线子系统接口绑定某一个委托的控制其…

产品经理课程

原型工具 一、土耳其机器人 这个说法来源于 1770 年出现的一个骗局&#xff0c;一个叫沃尔夫冈冯肯佩伦&#xff08;Wolfgang von Kempelen&#xff09;的人为了取悦奥地利女皇玛丽娅特蕾莎&#xff08;Maria Theresia&#xff09;&#xff0c;“制造”了一个会下国际象棋的机…

nginx中的limit_req 和 limit_conn

在 Nginx 中&#xff0c;limit_req 和 limit_conn 是两个用于限制客户端请求的指令&#xff0c;它们分别用于限制请求速率和并发连接数。 limit_req limit_req 用于限制请求速率&#xff0c;防止客户端发送过多请求影响服务器性能。它通过 limit_req_zone 指令定义一个共享内存…

基于winform的串口调试助手

目录 一、串口助手界面设计 1.1 串口配置 1.2 接收配置 1.3 发送配置 1.4 接收窗口和发送窗口 1.5 状态显示窗口 1.6 串口通讯控件 二、程序编写 2.1 端口号自动识别并显示在端口号下拉框 功能说明&#xff1a; 2.2 波特率下拉框显示 2.3 数据位下拉框显示 2.4 校…

Docker基础2

如需转载&#xff0c;标记出处 本次我们将下载一个 Docker 镜像&#xff0c;从镜像中启动容器 上一章&#xff0c;安装 Docker 时&#xff0c;获得两个主要组件&#xff1a; Docker 客户端 Docker 守护进程&#xff08;有时称为“服务器”或“引擎”&#xff09; 守护进程实…

Rocketmq2

一、生产者端防丢失 1. 发送方式选择 同步发送&#xff1a;使用 send() 方法&#xff0c;等待 Broker 确认响应&#xff08;SendResult&#xff09;&#xff0c;确保消息已成功发送。异步发送&#xff1a;使用 sendAsync() 方法并设置回调函数&#xff0c;处理发送成功 / 失败…

RabbitMQ详解,RabbitMQ是什么?架构是怎样的?

目录 一,RabbitMQ是什么? 二,RabbitMQ架构 2.1 首先我们来看下RabbitMQ里面的心概念Queue是什么? 2.2 交换器Exchange 2.3 RabbitMQ是什么? 2.4 重点看下优先级队列是什么? 三,RabbitMQ集群 3.1 普通集群模式 3.2 镜像队列集群 一,RabbitMQ是什么? 假设我们程序…

【一步步开发AI运动APP】六、运动计时计数能调用

之前我们为您分享了【一步步开发AI运动小程序】开发系列博文&#xff0c;通过该系列博文&#xff0c;很多开发者开发出了很多精美的AI健身、线上运动赛事、AI学生体测、美体、康复锻炼等应用场景的AI运动小程序&#xff1b;为了帮助开发者继续深耕AI运动领域市场&#xff0c;今…

MySQL——DQL的多表查询

一、交叉连接 标准语法&#xff1a;select * from 表1 cross join 表2 where 表1.公共列 表2.公共列; 简单语法&#xff1a;select * from 表1 , 表2 where 表1.公共列 表2.公共列; 公共列&#xff1a;两张表具有相同含义的列&#xff0c;不是列名一样。 …