ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

cosmos 项目 Java 语言专题:深入理解二维 ArrayList(2D Array List)的声明、常用操作与适用场景

cosmos 项目 Java 语言专题:深入理解二维 ArrayList(2D Array List)的声明、常用操作与适用场景 cosmos 项目 Java 语言专题深入理解二维 ArrayList2D Array List的声明、常用操作与适用场景【免费下载链接】cosmosWorlds largest Contributor driven code dataset | Used in Quark Search Engine, OpenGenus IQ, OpenGenus Visual Project项目地址: https://gitcode.com/gh_mirrors/co/cosmos二维 ArrayList 是 Java 集合框架中“动态二维结构”的典型实现它以ArrayListArrayListT的形式用多个一维列表拼装成行-列模型无需像原生数组那样预先固定大小元素持续添加时容量会自动增长。在 cosmos 仓库的 Java 语言目录中Readme.md 系统介绍了这一数据结构并配套提供了可直接运行的示例源码。读完本文你将掌握 2D ArrayList 的声明方式、逐行初始化技巧、核心 API 的调用细节以及它与原生 2D 数组int[][]在内存模型与适用场景上的本质差异。一、从动态数组到二维 ArrayList核心概念ArrayList是数组Array的动态版本。原生数组在声明时必须预定义长度而 ArrayList 内部维护一个可扩容的底层数组当元素数量超过当前容量时会自动增长因此使用者在多数场景下无需关心容量上限。将这一思想推广到二维就得到2D ArrayList它本质上是“存放列表的列表”每个外层元素都是一个独立的一维ArrayList。原文档给出的最简定义如下ArrayListArrayListInteger arrLL new ArrayListArrayListInteger ();从类型结构看arrLL的每一个元素都是ArrayListInteger因此可以把它理解为“由多个动态行组成的动态二维表”。相比原生int[][]它的行本身也是动态的——每一行既可以有不同长度也可以在运行时按需添加、删除或整体移除。按照原文档的划分ArrayList 家族主要有两类常见变体1-D Array List一维 ArrayList即通常所说的 ArrayListMultidimensional Array List多维 ArrayList。其中2-D Array List是最简单、最常用的多维形态也是本文的讲解对象。仓库中与之形成对照的另一份文档 readme-2DArray.md 则介绍原生 2D 数组int[][] arr new int[10][20];两条声明放在一起恰好展示了“静态二维”与“动态二维”两种建模思路的区别。二、声明与初始化如何正确“开辟”二维 ArrayList声明ArrayListArrayListInteger只创建了一个空的“容器”此时它内部一个行都还没有。想要真正使用二维结构必须逐行为外层列表添加一维 ArrayList 实例否则对arrLL.get(i)的任何访问都会抛出IndexOutOfBoundsException。仓库示例 2d-array-list-java.java 演示了标准的初始化流程// 创建 2D ArrayList ArrayListArrayListInteger arrLL new ArrayListArrayListInteger (); // 分配第 0 行通过 new 关键字创建内层列表默认值为空 arrLL.add(new ArrayListInteger()); // 在第 0 行索引 0 处写入 13覆盖默认状态 arrLL.get(0).add(0, 13);这里有两个关键点值得注意必须先 add 行再对行内 add 元素。arrLL.add(new ArrayListInteger())负责向“行集合”中添加一个空行随后arrLL.get(0)取出该行引用再调用其add(0, 13)在指定下标插入元素。每行相互独立。外层列表只保存内层列表的引用任何一行的长度变化增删元素都不会影响其他行这正是“二维”中两个维度都具备动态性的来源。如果需要构造一个“n 行 × m 列”的规则二维结构可在初始化阶段用循环为每一行创建列表并填充占位值例如ArrayListArrayListInteger grid new ArrayList(); int rows 3, cols 4; for (int i 0; i rows; i) { grid.add(new ArrayList()); for (int j 0; j cols; j) { grid.get(i).add(0); // 以 0 作为默认值占位 } }这种“先铺行、再填格”的模式是 2D ArrayList 最常见的构造方式也是与原生int[][]声明后即可直接赋值默认填充 0之间最直观的差异。三、基于仓库源码的完整实操常用 API 逐项解析2d-array-list-java.java 不仅是初始化演示还依次展示了 2D ArrayList 在“二维视角”下最常用的方法。下面结合源码逐一解析。3.1 整体输出toString 直接打印二维结构System.out.println(2D ArrayList :); System.out.println(arrLL);ArrayList重写了toString()嵌套列表会输出类似[[13]]的嵌套括号形式因此二维结构可以一次性打印无需手写双重循环。这是 ArrayList 相对原生数组打印数组名只会得到[I1b6d3586这类内存标识在调试体验上的明显优势。3.2 行内查找indexOf 与 lastIndexOfint ans arrLL.get(0).indexOf(13); System.out.println( Index of element 13 is ans); int ans2 arrLL.get(0).lastIndexOf(13); System.out.println( Last Index of element 13 is ans2);arrLL.get(0)取得第 0 行这个一维列表indexOf(13)返回该行中 13 首次出现的下标不存在时返回 -1lastIndexOf(13)返回该行中 13 最后一次出现的下标。这两个方法把二维查询拆解为“先定位行再在行内线性扫描”时间复杂度为 O(行内元素数)。3.3 整行删除remove 按行索引移除arrLL.remove(0); System.out.println(arrLL);remove(0)删除的是整行即外层列表的第 0 个元素随后原来的第 1 行自动前移补位。这是 2D ArrayList 相对原生数组最灵活的地方——原生数组无法在运行时收缩维度而 2D ArrayList 可以随时增删整行。3.4 元素存在性检查contains源码末尾通过 contains 判断某元素是否存在于指定行System.out.println(x.get(0).contains(13)); System.out.println(x.get(0).contains(1));需要提醒的是从源码结构看此处使用的变量x在文件内并未声明前文一直使用arrLL且第 0 行刚被remove(0)删除因此这两行若直接编译运行会因变量未定义而失败。这也反过来提醒读者两条实战要点行删除后原有的行下标会整体前移继续用旧下标访问可能得到错误的行引用行集合的变量应保持命名一致避免“抄写时引入未声明变量”这类低级错误。若将x替换为arrLL并调整行下标contains(13)的返回结果即为该行是否包含 13 的布尔判断。3.5 其他高频 API 一览除上述方法外2D ArrayList 还继承自AbstractList的常用能力方法作用在二维场景中的语义add(ArrayListT row)向末尾追加元素新增一行add(int index, ArrayListT row)在指定下标插入元素在指定行位置插入一行get(int row)按下标取元素取出一整行ArrayListTset(int row, ArrayListT newRow)替换指定下标元素整行替换size()返回元素个数返回行数isEmpty()是否为空是否无行clear()清空所有元素删除全部行remove(int index)删除指定下标元素删除整行结合内层列表还能实现“按坐标读写单个格子”arrLL.get(row).get(col)读取第 row 行第 col 列的值arrLL.get(row).set(col, value)写入该位置——这一组合本质上等价于二维数组的下标访问arr[row][col]。四、与原生 2D 数组的对比内存模型与取舍仓库同时收录了原生 2D 数组的实现 2d-array.java 与配套说明 readme-2DArray.md。该示例从用户输入读取行数、列数与矩阵元素再按行列打印int[][] arr new int[rows][columns]; // 遍历赋值 for (int i 0; i arr.length; i) { for (int j 0; j arr[0].length; j) { arr[i][j] s.nextInt(); } } // 遍历打印 for (int i 0; i arr.length; i) { for (int j 0; j arr[0].length; j) { System.out.print(arr[i][j] ); } System.out.println(); }两类二维结构的主要差异可以归纳如下维度原生 2D 数组int[][]2D ArrayListArrayListArrayListT行数声明时固定不可变动态可随时增删列数/行长固定矩形不可变每行独立、长度可变初始默认值数值类型自动为 0/false元素默认无需显式 add 行访问性能连续内存、直接下标寻址更快多层引用间接寻址有装箱与扩容开销内存开销低较高每行一个对象 自动装箱 Integer 对象类型安全基本类型可直接存放泛型不能直接用基本类型需用包装类灵活度低高适合“行数/列数动态变化”的场景从复杂度角度看原生 2D 数组的随机访问是严格 O(1)2D ArrayList 的get(row)与内层get(col)同样是 O(1)底层为数组索引但由于存在引用链与潜在的扩容搬移常数因子更大而行/列的插入与删除在 2D ArrayList 中可能触发整行或整列的元素搬移代价为 O(n)。五、优点与缺点总结综合原文档的定位与上述源码分析2D ArrayList 的优劣可以归纳如下。优点无需预定义尺寸行与列均可按需增长天然适配“数据规模未知、逐步累积”的读取流程行结构独立支持“参差不齐”的二维结构每行列数不同而原生二维数组必须是规则的矩形丰富的内置 APIadd、remove、indexOf、contains、toString等方法开箱即用配合Collections工具类还能对每行排序、反转代码表达力强调试友好整体println即可输出二维结构便于快速验证中间结果。缺点性能开销泛型只能使用引用类型基本类型元素会经历自动装箱autoboxing频繁读写时产生对象创建与 GC 压力多层 ArrayList 的引用间接寻址也慢于连续内存的原生数组内存占用每个内层列表都是一个独立对象外加装箱产生的Integer实例内存密度显著低于int[][]代码冗余声明与初始化需要显式逐行new ArrayList()比int[][]的一行声明繁琐误用风险未初始化行就访问get(i)会抛异常行删除导致的下标前移、遍历时修改结构等行为需要开发者格外谨慎。选型建议数据规模已知且固定、性能敏感的数值计算如矩阵运算优先选择原生int[][]而行数/列数动态变化、需要频繁插入删除整行、或对可读性与调试便利性要求更高的场景如构建邻接表、表格型数据处理2D ArrayList 是更合适的选择。六、实践要点与注意事项结合仓库示例与 Java 集合框架的行为在项目中使用 2D ArrayList 时建议遵循以下实践先建行、后填格任何arrLL.get(row)调用前必须确保该行已被add(new ArrayList())创建否则越界注意包装类陷阱ArrayListInteger中比较元素是否相等应使用equals或Integer的缓存范围 -128~127 之外不要依赖contains/indexOf内部已按equals处理可直接使用删除行后下标前移remove(row)之后原 row1 及其后的行整体前移遍历删除时应从后往前删避免漏删或越界预估容量减少扩容若已知大致行数与行内元素规模可在构造时传入初始容量如new ArrayList(rows)减少扩容搬移次数优先用增强 for 或迭代器遍历遍历时若需增删元素使用显式Iterator并调用iterator.remove()避免ConcurrentModificationException。2D ArrayList 是理解“容器组合”与“动态多维结构”的最佳入门示例也是许多复杂数据模型如图的邻接表、动态表格的构建基石。掌握其声明方式、逐行初始化的关键步骤与常用 API 的二维语义就能在合适的场景中用它替代原生二维数组写出更灵活、更易维护的 Java 代码。【免费下载链接】cosmosWorlds largest Contributor driven code dataset | Used in Quark Search Engine, OpenGenus IQ, OpenGenus Visual Project项目地址: https://gitcode.com/gh_mirrors/co/cosmos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表