Java常用集合类:ArrayList
1、知识点
1、ArrayList底层数组默认初始化大小为10,但是使用ArrayList的无参构造函数的时候,并没有马上进行扩容,我们查看源码就会发现,无参构造函数只是将ArrayList中的DEFAULTCAPACITY_EMPTY_ELEMENTDATA(一个空数组)赋值给了底层数组。
2、ArrayList是非线程安全的,是因为ArrayList底层数组,及维护数组的属性等信息,在修改的时候并没有进行同步控制(加锁),所以多线程环境下对这些数据进行修改的时候是互相不可见的,他们修改的值也存在互相覆盖的问题。
3、如果在增强for循环或者迭代器中使用ArrayList时,数组被改变会马上抛出异常。这里说的for循环只有增强的for循环,不包括普通for循环,因为增强for循环底层使用的是迭代器(iterator)ArrayList在实现Iterable接口时,加入了版本号进行控制(ArrayList每次对数组进行修改的操作都会同时增加版本号),迭代过程中会对版本号进行校验,如果与预期版本号不符就会抛出异常。
4、源码中的变量size并不是指的是ArrayList中数组的大小,而是数组中元素的个数,这个看源码的注释就能明白。这个也很好理解,当你初始化一个容量为100的数组的时候(new ArrayList(100);
),当没有添加任何元素时调用size方法,其返回值是0;这个问题其实是要说你要明白两个概念:大小和容量。
5、当采用添加初始化数据的方式初始化ArrayList时(ArrayList(Collection<? extends E> c)
),如果添加的集合中元素不是Object类型(如:数组类型),当调用toArray方法将这个集合转换为Object[]后再对该数组进行修改时,会报数组存储异常(ArrayStoreExecption)。
6、ArrayList在按照对象删除元素(remove(Object obj))的时候,其实也是通过循环并对比的方式来完成的,这里要注意的是这里用于比较的方法是equals方法,那么当这个类是我们自定义的类时就需要特别注意了,如果有这种使用场景那就需要重写equals方法了,比如你自定义的类Student,User。。。
7、说一下扩容:
无参构造函数,会创建一个空数组,当第一次add元素时会初始化为大小为10(默认初始化大小)的数组。
扩容时机:就是当ArrayList中数组满的时候,再加元素时会进行扩容。就是比如数组长度是10,加第11个元素的时候;或者长度是10,现在有9个元素,再一次性加2个元素的时候就会扩容。
扩容大小一般是当前数组大小的1.5倍;扩容的临界值是int的最大值减去8,也就是说ArrayList中允许的数组最大长度为int的最大值减去8。这里可以查看一下jdk1.8源码(网上有些教程中说是int最大值,略微有点不准确):
/*** The maximum size of array to allocate.* Some VMs reserve some header words in an array.* Attempts to allocate larger arrays may result in* OutOfMemoryError: Requested array size exceeds VM limit*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
上面这个图其实就是扩容的源码,我们看到其实ArrayList在扩容的时候其实就是看最小容量(minCapacity这个值,也是你向数组中加入元素后元素的个数),有没有大于当前数组大小。如果大于,那就扩容到旧数组的1.5倍,如果旧数组1.5倍还是不够那就扩容到最小容量(比如初始化一个大小为10的数组,结果一次性加入18个元素),如果大于了ArrayList允许的最大长度,那大小就不再增长了。
ArrayList提供了两个空数组,一个是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,一个是EMPTY_ELEMENTDATA,空参构造函数将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给底层数组elementData,而new ArrayList(0)会将EMPTY_ELEMENTDATA赋值给elementData(看下面的图片),这里只是做个区分,好在扩容的时候为空参构造函数扩容为默认长度10的数组(这个可以看上面图片第一个方法)。
扩容其实就是创建一个新的大一些的数组,然后把旧数组中的数据拷贝到新的数组中去,用新的数组代替旧的数组。调用的是Arrays.copyOf()方法,这个方法又是调用了native方法:arraycopy,其实删除ArrayList中删除元素也是通过该方法进行删除操作的。
为什么不是每次扩容都是直接扩容到正好的大小呢?其实我们看到扩容其实就是不断的创建更大的数组来代替原来的数组,并且将旧值复制到新的数组,这样的操作其实是很耗资源的,为了节省频繁复制的开销就需要多预留一定的空间;那么当我们在开发时如果能预先知道我们要创建的数组有多大,就直接在初始化的时候指定数组大小,这样就可以达到节约系统资源的效果。还有就是如果能采用addAll()方法就不要使用循环add()的方式,这样也可以减少扩容次数。
这其中还隐藏着一个小细节,就是0.5倍的这个扩容的量,我们可以发现当数组较小的时候进行扩容其实每次增长的并不是特别多,所以不会占用太多空间;当数组较大时每次扩容增长的就比较多,这样在数据增长很快的情况下就不需要频繁扩容。
Java常用集合类:ArrayList相关推荐
- Java 常用集合类学习
Java 常用集合类学习 1 Collection集合 1.1 Collection集合简介 1.2 Collection集合基本操作 1.3 Collection集合迭代 2 List集合 2.1 ...
- java常用集合类详解(有例子,集合类糊涂的来看!)
Framework 集合框架是一个统一的架构,用来表示和操作集合. 集合框架主要是由接口,抽象类和实现类构成. 接口:蓝色:实现类:红色 Collection |_____Set(HashSet) | ...
- 温故而知新--Java基础(三):Java常用集合类(上)
前言: 数组和集合的区别: 数组声明了器元素的类型,集合不需要声明. 数组创建之后大小固定,不能扩容,集合大小不固定,可以根据需要动态扩容,集合里提供更多的成员方法,满足更多的需求. 数组存放的数据类 ...
- Java基础-集合类-ArrayList retainAll() 方法
一. retainAll 方法 retainAll() 方法用于保留 arraylist 中在指定集合中也存在的那些元素,也就是删除指定集合中不存在的那些元素. retainAll() 方法的语法为: ...
- Java常用API——ArrayList
PS:使用Ctrl+鼠标左键可以查看源码 用数组存储对象 创建Person类 package ArrayList_test;public class Person {private int age;p ...
- Java常用集合笔记
最近事情比较少,闲暇之余温习巩固一下Java的一些基础知识,并做一些笔记, Java常用集合, 主要参考的这篇文章:Java常用集合 ArrayList/Vertor 1. ArrayList 的主要 ...
- java 类 函数,java常用类和函数
JAVA中常用类的常用方法_计算机软件及应用_IT/计算机_专业资料.. JAVA 中常用类的常用方法 一. java.lang.Object 类 1. clone ()方法 创建并返回此对象的... ...
- java常用的集合对象_java常用实体类、集合类
java常用实体类.集合类 [转自51cto博客jichangwei的BLOG] 1:String类,字符串是常量,他们的值在创建之后不能更改,可以共享. equals()用来比较两个字符串的值,== ...
- java面试题29 牛客 以下关于集合类ArrayList、LinkedList、HashMap描述
java面试题29 牛客 以下关于集合类ArrayList.LinkedList.HashMap描述错误的是() A HashMap实现Map接口,它允许任何类型的键和值对象,并允许将null用作键或 ...
最新文章
- tensorflow 模型预训练后的参数restore finetuning
- 自己设计java流程审核_关于工作流引擎取回审批的设计方案与实现过程
- tableau必知必会之学做直观的华夫饼图(Waffle Chart)
- word保存时标题变成黑框(mac版本)
- 报告解读丨细数万亿企服市场发展史,行业发展新趋势
- MAPREDUCE的实战案例
- python webui测试ie浏览器环境配置_python+selenium做ui自动化测试用法必会
- 在Visual Studio Code配置GoLang开发环境
- 基于Windows NBL配置WebInterface
- 虚拟机怎么启动共享文件服务器,VMware虚拟机中ubuntu启用本地文件共享的设置方法...
- 计算机芯片级维修包括哪些,电脑芯片级维修教程
- 小程序轮播图测试用例
- vlan的基本指令_vlan划分命令
- stream流倒序排序_Stream流排序
- XP需要计算机管理权限,xp无法无法使用管理员权限运行软件的解决步骤
- RationalDMIS 2020 网络报表/网络编程连接设置
- 【中移芯昇】3. uart读写
- Ubantu 安装 Oracle JDK
- Modelsim搭建只有driver的UVM验证平台
- 2017 java 面试大全
热门文章
- 下一个倒下的手机厂商将是魅族?最大专卖店已变身华为
- 中国移动发布5G权威测评:华为Mate 20 X 以强劲性能拔得头筹
- 苹果宣布取消AirPower 因技术难题无法攻克
- 全志R40 UBOOT 2014.07【原创】
- Android Studio中手机能连接上ADB不过一直跑不起来(或者应用出现短暂的白屏)
- java怎么实现两个对象内容的交换
- win7 32位php安装包下载地址,appserv官方下载|AppServ(php环境安装包)下载v8.6 64位/32位 支持win7/win8/win10_ IT猫扑网...
- php 目录文件大小,利用php怎么对目录文件的大小进行统计
- centos7 安装mysql8_CentOS 下 MySQL 8.0 安装部署,超详细!
- 【Elasticsearch】十九种Elasticsearch字符串搜索方式终极介绍 各种 查询