在开始本章内容之前,这里先简单介绍下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源码解读的更多相关文章

  1. java集合系列之ArrayList源码分析

    java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...

  2. Java集合系列[1]----ArrayList源码分析

    本篇分析ArrayList的源码,在分析之前先跟大家谈一谈数组.数组可能是我们最早接触到的数据结构之一,它是在内存中划分出一块连续的地址空间用来进行元素的存储,由于它直接操作内存,所以数组的性能要比集 ...

  3. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  4. java集合系列之HashMap源码

    java集合系列之HashMap源码 HashMap的源码可真不好消化!!! 首先简单介绍一下HashMap集合的特点.HashMap存放键值对,键值对封装在Node(代码如下,比较简单,不再介绍)节 ...

  5. java集合系列之LinkedList源码分析

    java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...

  6. Java集合系列[3]----HashMap源码分析

    前面我们已经分析了ArrayList和LinkedList这两个集合,我们知道ArrayList是基于数组实现的,LinkedList是基于链表实现的.它们各自有自己的优劣势,例如ArrayList在 ...

  7. 【java集合总结】-- ArrayList源码解析

    一.前言 要想深入的了解集合就必须要通过分析源码来了解它,那如何来看源码,要看什么东西呢?主要从三个方面: 1.看继承结构 看这个类的继承结构,处于一个什么位置,不需要背记,有个大概的感觉就可以,我自 ...

  8. Java集合系列:-----------03ArrayList源码分析

    上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...

  9. Java集合系列[2]----LinkedList源码分析

    上篇我们分析了ArrayList的底层实现,知道了ArrayList底层是基于数组实现的,因此具有查找修改快而插入删除慢的特点.本篇介绍的LinkedList是List接口的另一种实现,它的底层是基于 ...

随机推荐

  1. 学习sbtenv

    背景 最近由于工作需要, 我总是在不同的scala项目间流动开发. 这就遇到一个很棘手的问题, 这几个项目用的sbt版本不一致, 老项目用的是 sbt 0.13.15, 新项目用的是 sbt 1.0. ...

  2. VB6 red write DB using Microsoft DAO 3.6 Object Library

    ' -----------------------------read db Private Sub Form_Load() 'MsgBox App.Path & "\wgscd.m ...

  3. [Oracle]ORA-01499的处理

    如果出现 ORA-01499,说明 table 和 index之间的相互参照出了错: http://iderror.com/errors/oracle/oracle-db/ora-00900-to-o ...

  4. 用 eric6 与 PyQt5 实现python的极速GUI编程(系列03)---- Drawing(绘图)(3)-- 画线

    [概览] 本文实现如下的程序:(在窗体中绘画出各种不同风格的线条) 主要步骤如下: 1.在eric6中新建项目,新建窗体 2.(自动打开)进入PyQt5 Desinger,编辑图形界面,保存 3.回到 ...

  5. [Deep-Learning-with-Python]神经网络入手学习[上]

    神经网络入手[上] [x] 神经网络的核心部分 [x] Keras介绍 [ ] 使用Keras解决简单问题:分类和回归 神经网络剖析 神经网络的训练与下列对象相关: 网络层Layers,网络层结合形成 ...

  6. imu标定 imu_tk

    1. 首先标定加速度计,这是imu加速度计xyz三个轴在标定过程中的读数: 标定结果: 2. 利用加速度计的标定结果,标定陀螺仪,结果: 也可以使用港科大开源的一个工具: https://github ...

  7. Web开发框架趋势

    Node.js增长很快,已经冒尖了 ASP.NET MVC 发展平稳(平稳很重要) Spring MVC沾着Spring的光,渐渐超越了Struts 2 Struts作为一个整体(Struts 1 和 ...

  8. Unity优化方向——优化Unity游戏中的图形渲染(译)

    CPU bound:CPU性能边界,是指CPU计算时一直处于占用率很高的情况. GPU bound:GPU性能边界,同样的是指GPU计算时一直处于占用率很高的情况. 原文:https://unity3 ...

  9. easyx图形库做贪吃蛇游戏

    编程总是对着一个黑窗口,可以说是非常乏味了,于是喵喵就翻出来了以前用easyx图形库做图形界面的贪吃蛇游戏. 不过大家只是当做提高编程的乐趣来学习吧,想进一步做的话可以学习QT,还有其他的框架. 这是 ...

  10. CHAPTER 5 ‘The Master of Those Who know’ Aristotle 第5章 “有识之士的大师” 亚里士多德

    CHAPTER 5 ‘The Master of Those Who know’ Aristotle 第5章 “有识之士的大师” 亚里士多德 ‘All men by nature desire to ...