深入理解JAVA集合系列四:ArrayList源码解读
在开始本章内容之前,这里先简单介绍下List的相关内容。
List的简单介绍
有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。列表通常允许重复的元素,且允许null元素的存放。
ArrayList的简单介绍
JDK中这样定义ArrayList:List接口的大小可变数据的实现。
主要有以下特点:
1、有序
2、线程不安全
3、元素可以重复
4、可以存放null值
顾名思义,取名ArrayList是因为其内部是用一个大小可变的数组存储元素,也就是说底层是一个动态数组。
add方法解读
List<String> li = new ArrayList<String>();
li.add("33");
先看这个构造函数:
public ArrayList() {
this(10);
}
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
这里先定义默认的初始容量为10,然后构建了一个容量为10的数组elementData;这个elementData数组就是ArrayList底层存放元素的数组,且元素是Object类型。该数组的源码定义也了解下:
private transient Object[] elementData;
再来看ADD方法:
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
1、第6行的扩容部分后面再解释,其余的比较简单,我们直接看第7行。调用的是System.arraycopy的方法。
2、第一次看到这个方法有点搞不懂,先来解释下:System.arraycopy(src, srcPos, dest, destPos, length);
第一个参数表示的是要被复制的数组;第二个参数表示数组中从第几个元素开始复制。
第三个参数表示复制到哪个数组;第四个参数表示复制到那个数组从哪个元素开始;第五个参数表示要复制的长度
3、解释完这个方法就很清楚了,add方法就是将数组中待添加元素的位置后面所有的元素(包括该位置),通过copy的复制方法,全部后移一个位置。然后将待添加的元素放到指 定的位置上。当然这个数组可能是原数组,也可能是经过第6行代码扩容之后新的数组。
扩容
扩容,动态扩容,也就是前面所提到的ArrayList的底层是由一个动态变化的数组实现的。
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
1、我们看扩容的算法,也就是在旧容量的基础上,扩大1.5倍再加上1。至于为什么是这样一个算法,我也没明白。但是JDK开发人员肯定是在这方面做过思考的:不能一次性扩容太大,会造成内存空间的浪费;也不能扩容得不够,否则下一次扩容的操作会很快到来。我猜想应该是基于这样的考虑才设计了这样一个算法。
2、扩容结束后,就是将旧数组里面的元素全部复制到新的数组里。并且新数组还是通过elementData变量来引用。
remove方法解读
我们先来看下该方法的源码:
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
其实这个remove的方法处理的过程也比较简单:
1、第2行代码是用来检测数组下标是否越界。
2、然后取出该位置上的数组元素。
3、通过arryCopy方法将待删除元素之后的所有元素往前一个位置复制。(注意,这个动作是先复制,然后粘贴)。
4、这个时候最后一个位置上的元素就是多余的,所以才有了第11行的处理,将其置为null。
ArrayList的优缺点
1、底层是由数组实现的,便于随机访问。
2、顺序添加元素性能比较高,相当于每次在数组最后添加一个元素、
3、插入元素、删除元素的时候,会涉及到元素的复制,即调用arrayCopy方法,如果复制的元素比较多,则这样就比较消耗性能。
总结来说:ArrayList的优势是随机访问、顺序添加。
深入理解JAVA集合系列四:ArrayList源码解读的更多相关文章
- java集合系列之ArrayList源码分析
java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...
- Java集合系列[1]----ArrayList源码分析
本篇分析ArrayList的源码,在分析之前先跟大家谈一谈数组.数组可能是我们最早接触到的数据结构之一,它是在内存中划分出一块连续的地址空间用来进行元素的存储,由于它直接操作内存,所以数组的性能要比集 ...
- Java集合系列[4]----LinkedHashMap源码分析
这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...
- java集合系列之HashMap源码
java集合系列之HashMap源码 HashMap的源码可真不好消化!!! 首先简单介绍一下HashMap集合的特点.HashMap存放键值对,键值对封装在Node(代码如下,比较简单,不再介绍)节 ...
- java集合系列之LinkedList源码分析
java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...
- Java集合系列[3]----HashMap源码分析
前面我们已经分析了ArrayList和LinkedList这两个集合,我们知道ArrayList是基于数组实现的,LinkedList是基于链表实现的.它们各自有自己的优劣势,例如ArrayList在 ...
- 【java集合总结】-- ArrayList源码解析
一.前言 要想深入的了解集合就必须要通过分析源码来了解它,那如何来看源码,要看什么东西呢?主要从三个方面: 1.看继承结构 看这个类的继承结构,处于一个什么位置,不需要背记,有个大概的感觉就可以,我自 ...
- Java集合系列:-----------03ArrayList源码分析
上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...
- Java集合系列[2]----LinkedList源码分析
上篇我们分析了ArrayList的底层实现,知道了ArrayList底层是基于数组实现的,因此具有查找修改快而插入删除慢的特点.本篇介绍的LinkedList是List接口的另一种实现,它的底层是基于 ...
随机推荐
- [转]使用CallerMemberName简化InotifyPropertyChanged的实现
原文:https://www.cnblogs.com/TianFang/p/3381484.html 在WPF中,当我们要使用MVVM的方式绑定一个普通对象的属性时,界面上往往需要获取到属性变更的通知 ...
- spring-data-jpa快速入门(一)——整合阿里Druid
一.概述 官网:https://projects.spring.io/spring-data-jpa/ 1.什么是spring-data-jpa Spring Data JPA, part of th ...
- 多线程Java Socket编程示例
package org.merit.test.socket; import java.io.BufferedReader; import java.io.IOException; import jav ...
- pwd的实现20155301
pwd的实现 任务要求: 1) 学习pwd命令 2) 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3) 实现mypwd 4) 测试mypwd 实现过程 1)首先查看是否有有用 ...
- c# 抓取和解析网页,并将table数据保存到datatable中(其他格式也可以,自己去修改)
使用HtmlAgilityPack 基础请参考这篇博客:https://www.cnblogs.com/fishyues/p/10232822.html 下面是根据抓取的页面string 来解析并保存 ...
- Scikit-Learn机器学习入门
现在最常用的数据分析的编程语言为R和Python.每种语言都有自己的特点,Python因为Scikit-Learn库赢得了优势.Scikit-Learn有完整的文档,并实现很多机器学习算法,而每种算法 ...
- jquery 配合 jsp 实现 ajax 要注意的问题
(这一次 jq 无法执行的原因竟然是: 没导入 jq 的 js 文件!!!!!!!!!!!!!!) 今天在写一个 select change 实现来 ajax 时,发现 jq 无法执行,网上查了下,发 ...
- 关于 Git SSH 使用的项目实践
Git 是分布式的代码管理工具,远程的代码管理是基于 SSH 的,所以要使用远程的 git 则需要SSH的配置. 一.简述 访问 Git 仓库可以使用 SSH Key 的方式,首先需要生成 Key. ...
- 关于big-endian和little-endian
详解大端模式和小端模式 一.大端模式和小端模式的起源 关于大端小端名词的由来,有一个有趣的故事,来自于Jonathan Swift的<格利佛游记>:Lilliput和Blefuscu这两个 ...
- 禁用AxWebBrowser右键菜单
出处:http://stackoverflow.com/questions/41781647/disabling-the-axwebbrowser-context-menu-vb-net 通过底层消息 ...