Java 中 ArrayList 类的用法

本贴最后更新于 2305 天前,其中的信息可能已经水流花落

1、什么是 ArrayList 
ArrayList 就是传说中的动态数组,用 MSDN 中的说法,就是 Array 的复杂版本,它提供了如下一些好处: 
动态的增加和减少元素 
实现了 ICollection 和 IList 接口 
灵活的设置数组的大小

2、如何使用 ArrayList 
最简单的例子: 
ArrayList List = new ArrayList(); 
for( int i=0;i <10;i++ ) //给数组增加 10 个 Int 元素 
List.Add(i); 
//..程序做一些处理 
List.RemoveAt(5);//将第 6 个元素移除 
for( int i=0;i <3;i++ ) //再增加 3 个元素 
List.Add(i+20); 
Int32[] values = (Int32[])List.ToArray(typeof(Int32));//返回 ArrayList 包含的数组

这是一个简单的例子,虽然没有包含 ArrayList 所有的方法,但是可以反映出 ArrayList 最常用的用法

3、ArrayList 重要的方法和属性 
1)构造器 
ArrayList 提供了三个构造器: 
public ArrayList(); 
默认的构造器,将会以默认(16)的大小来初始化内部的数组 
public ArrayList(ICollection); 
用一个 ICollection 对象来构造,并将该集合的元素添加到 ArrayList 
public ArrayList(int); 
用指定的大小来初始化内部的数组

2)IsSynchronized 属性和 ArrayList.Synchronized 方法 
IsSynchronized 属性指示当前的 ArrayList 实例是否支持线程同步,而 ArrayList.Synchronized 静态方法则会返回一个 ArrayList 的线程同步的封装。 
如果使用非线程同步的实例,那么在多线程访问的时候,需要自己手动调用 lock 来保持线程同步,例如: 
ArrayList list = new ArrayList(); 
//... 
lock( list.SyncRoot ) //当 ArrayList 为非线程包装的时候,SyncRoot 属性其实就是它自己,但是为了满足 ICollection 的 SyncRoot 定义,这里还是使用 SyncRoot 来保持源代码的规范性 

list.Add( “Add a Item” ); 
}

如果使用 ArrayList.Synchronized 方法返回的实例,那么就不用考虑线程同步的问题,这个实例本身就是线程安全的,实际上 ArrayList 内部实现了一个保证线程同步的内部类,ArrayList.Synchronized 返回的就是这个类的实例,它里面的每个属性都是用了 lock 关键字来保证线程同步。

3)Count 属性和 Capacity 属性 
Count 属性是目前 ArrayList 包含的元素的数量,这个属性是只读的。 
Capacity 属性是目前 ArrayList 能够包含的最大数量,可以手动的设置这个属性,但是当设置为小于 Count 值的时候会引发一个异常。

4)Add、AddRange、Remove、RemoveAt、RemoveRange、Insert、InsertRange 
这几个方法比较类似 
Add 方法用于添加一个元素到当前列表的末尾 
AddRange 方法用于添加一批元素到当前列表的末尾 
Remove 方法用于删除一个元素,通过元素本身的引用来删除 
RemoveAt 方法用于删除一个元素,通过索引值来删除 
RemoveRange 用于删除一批元素,通过指定开始的索引和删除的数量来删除 
Insert 用于添加一个元素到指定位置,列表后面的元素依次往后移动 
InsertRange 用于从指定位置开始添加一批元素,列表后面的元素依次往后移动

另外,还有几个类似的方法: 
Clear 方法用于清除现有所有的元素 
Contains 方法用来查找某个对象在不在列表之中

其他的我就不一一累赘了,大家可以查看 MSDN,上面讲的更仔细 
5)TrimSize 方法 
这个方法用于将 ArrayList 固定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。 
6)ToArray 方法 
这个方法把 ArrayList 的元素 Copy 到一个新的数组中。 
4、ArrayList 与数组转换 
例 1: 
ArrayList List = new ArrayList(); 
List.Add(1); 
List.Add(2); 
List.Add(3);

Int32[] values = (Int32[])List.ToArray(typeof(Int32));

例 2: 
ArrayList List = new ArrayList(); 
List.Add(1); 
List.Add(2); 
List.Add(3);

Int32[] values = new Int32[List.Count]; 
List.CopyTo(values);

上面介绍了两种从 ArrayList 转换到数组的方法

例 3: 
ArrayList List = new ArrayList(); 
List.Add( “string” ); 
List.Add( 1 ); 
//往数组中添加不同类型的元素

object[] values = List.ToArray(typeof(object)); //正确 
string[] values = (string[])List.ToArray(typeof(string)); //错误

和数组不一样,因为可以转换为 Object 数组,所以往 ArrayList 里面添加不同类型的元素是不会出错的,但是当调用 ArrayList 方法的时候,要么传递所有元素都可以正确转型的类型或者 Object 类型,否则将会抛出无法转型的异常。

5、ArrayList 最佳使用建议 
这一节我们来讨论 ArrayList 与数组的差别,以及 ArrayList 的效率问题 
1)ArrayList 是 Array 的复杂版本 
ArrayList 内部封装了一个 Object 类型的数组,从一般的意义来说,它和数组没有本质的差别,甚

定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。 
6)ToArray 方法 
这个方法把 ArrayList 的元素 Copy 到一个新的数组中。 
4、ArrayList 与数组转换 
例 1: 
ArrayList List = new ArrayList(); 
List.Add(1); 
List.Add(2); 
List.Add(3);

Int32[] values = (Int32[])List.ToArray(typeof(Int32));

例 2: 
ArrayList List = new ArrayList(); 
List.Add(1); 
List.Add(2); 
List.Add(3);

Int32[] values = new Int32[List.Count]; 
List.CopyTo(values);

上面介绍了两种从 ArrayList 转换到数组的方法

例 3: 
ArrayList List = new ArrayList(); 
List.Add( “string” ); 
List.Add( 1 ); 
//往数组中添加不同类型的元素

object[] values = List.ToArray(typeof(object)); //正确 
string[] values = (string[])List.ToArray(typeof(string)); //错误

和数组不一样,因为可以转换为 Object 数组,所以往 ArrayList 里面添加不同类型的元素是不会出错的,但是当调用 ArrayList 方法的时候,要么传递所有元素都可以正确转型的类型或者 Object 类型,否则将会抛出无法转型的异常。

5、ArrayList 最佳使用建议 
这一节我们来讨论 ArrayList 与数组的差别,以及 ArrayList 的效率问题 
1)ArrayList 是 Array 的复杂版本 
ArrayList 内部封装了一个 Object 类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于 ArrayList 的许多方法,如 Index、IndexOf、Contains、Sort 等都是在内部数组的基础上直接调用 Array 的对应方法。 
2)内部的 Object 类型的影响 
对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往 ArrayList 里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。 
但是恰恰对于大多数人,多数的应用都是使用值类型的数组。 
消除这个影响是没有办法的,除非你不用它,否则就要承担一部分的效率损失,不过这部分的损失不会很大。 
3)数组扩容 
这是对 ArrayList 效率影响比较大的一个因素。 
每当执行 Add、AddRange、Insert、InsertRange 等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素 Copy 到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。 
例 1:比如,一个可能有 200 个元素的数据动态添加到一个以默认 16 个元素大小创建的 ArrayList 中,将会经过: 
162222 = 256 
四次的扩容才会满足最终的要求,那么如果一开始就以: 
ArrayList List = new ArrayList( 210 ); 
的方式创建 ArrayList,不仅会减少 4 次数组创建和 Copy 的操作,还会减少内存使用。

例 2:预计有 30 个元素而创建了一个 ArrayList: 
ArrayList List = new ArrayList(30); 
在执行过程中,加入了 31 个元素,那么数组会扩充到 60 个元素的大小,而这时候不会有新的元素再增加进来,而且有没有调用 TrimSize 方法,那么就有 1 次扩容的操作,并且浪费了 29 个元素大小的空间。如果这时候,用: 
ArrayList List = new ArrayList(40); 
那么一切都解决了。 
所以说,正确的预估可能的元素,并且在适当的时候调用 TrimSize 方法是提高 ArrayList 使用效率的重要途径。 
4)频繁的调用 IndexOf、Contains 等方法(Sort、BinarySearch 等方

法经过优化,不在此列)引起的效率损失 
首先,我们要明确一点,ArrayList 是动态数组,它不包括通过 Key 或者 Value 快速访问的算法,所以实际上调用 IndexOf、Contains 等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用 Hashtable 或 SortedList 等键值对的集合。 
ArrayList al=new ArrayList();

al.Add("How"); 
al.Add("are"); 
al.Add("you!");

al.Add(100); 
al.Add(200); 
al.Add(300);

al.Add(1.2); 
al.Add(22.8);

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3203 引用 • 8217 回帖
  • ArrayList
    5 引用 • 10 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone9891 via macOS

    每当执行 Add、AddRange、Insert、InsertRange 等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素 Copy 到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。

    我从很多地方听到过 说是 ArrayList 是 2 倍扩容的,我不知道是因为版本的原因还是最开始说这个的人 胡扯

    /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }

    专门 去看了源码证明了一下,扩容并不是双倍的,而是 1.5 倍 扩容。

    如上代码所示 (代码源于 java version "1.8.0_151"),扩容后的数组容量应该是 原容量 + (原容量 / 2)

  • hefeng

    难道这就是微软出品的 Java?

  • lizhongyue248 via Linux

    看这种文章好难受,代码和文字搅合在一起,看着都头疼,markdown 那么美观简洁的语法和显示偏偏不用

    1 回复
  • maixiaojie 1 评论
    作者

    感谢提出问题,很久之前写的文章了。给您的阅读带来麻烦还请谅解。

    真客气 😄
    88250
maixiaojie
如果哪天你累了告诉我 我背你。❤️

推荐标签 标签

  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 94 关注
  • Access
    1 引用 • 3 回帖 • 1 关注
  • OneNote
    2 引用 • 5 回帖 • 4 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 446 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 91 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1062 引用 • 3455 回帖 • 139 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    24 引用 • 33 回帖
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    90 引用 • 113 回帖
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 420 关注
  • danl
    192 关注
  • 印象笔记
    3 引用 • 21 回帖 • 1 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 115 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖 • 1 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 6 关注
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    20 引用 • 245 回帖 • 240 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    212 引用 • 358 回帖
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖 • 1 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    337 引用 • 324 回帖 • 2 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 482 关注
  • 安全

    安全永远都不是一个小问题。

    201 引用 • 818 回帖 • 1 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 65 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 293 关注