博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java集合源码分析系列-(一)ArrayList源码剖析
阅读量:6691 次
发布时间:2019-06-25

本文共 3973 字,大约阅读时间需要 13 分钟。

前言

今天介绍经常使用的一个Java集合类——ArrayList(基于JDK1.8.0_121)。ArrayList在工作和日常面试中经常被使用或者提到。总的来说,工作中使用ArrayList主要是因为动态数组的方便性,面试中出现ArrayList经常是和LinkedList/Vector一起出现,分析这三种集合的异同。

ArrayList类图

ArrayList类图

图片是直接从IntelliJ中导出来的,其中:蓝色线条意味着继承,绿色线条意味着接口实现。

ArrayList源码剖析

ArrayList定义

public class ArrayList
extends AbstractList
implements List
, RandomAccess, Cloneable, java.io.Serializable

我们首先需要明白并且牢记在内心的是,ArrayList本质上是一个数组,但是与Java中基础的数组所不同的是,它能够动态增长自己的容量

通过ArrayList的定义,可以知道ArrayList继承了AbstractList,同时实现了List,RandomAccess,Cloneable和java.io.Serializable接口。

继承了AbstractList类,实现了List,意味着ArrayList是一个数组队列,提供了诸如增删改查、遍历等功能。

实现了RandomAccess接口,意味着ArrayList提供了随机访问的功能。RandomAccess接口在Java中是用来被List实现,用来提供快速访问功能的。在ArrayList中,即我们可以通过元素的序号快速获取元素对象。
实现了Cloneable接口,意味着ArrayList实现了clone()函数,能被克隆。
实现了java.io.Serializable接口,意味着ArrayList能够通过序列化进行传输。

ArrayList关键属性

private static final int DEFAULT_CAPACITY = 10;transient Object[] elementData;private int size;

(1)ArrayList的默认容量为10;

(2)elementData是"Object类型的数组",所有ArrayList元素都保存在elementData中。在ArrayList中,elementData是一个动态数组。需要注意的是,ArrayList通过构造函数ArrayList(int initialCapacity)定义初始量initialCapacity;
(3)size是动态数组的实际大小。

//ArrayList带容量的构造函数public ArrayList(int initialCapacity) {    if (initialCapacity > 0) {    //新建一个容量为initialCapacity的数组        this.elementData = new Object[initialCapacity];    } else if (initialCapacity == 0) {        this.elementData = EMPTY_ELEMENTDATA;    } else {        throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    }}//ArrayList默认构造函数,默认为空public ArrayList() {    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}// 构造一个包含指定元素的listpublic ArrayList(Collection
c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; }}

第一个构造方法使用提供的initialCapacity来初始化elementData数组的大小。

第二个构造方法默认数组为0。
第三个构造方法则将提供的集合转成数组返回给elementData(返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[])。

ArrayList主要方法源码剖析

增加

public boolean add(E e) {    //扩容判断    ensureCapacityInternal(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;}public void add(int index, E element) {    //判断index是否越界,错误产生IndexOutOfBoundsException    rangeCheckForAdd(index);    //进行扩容检查    ensureCapacityInternal(size + 1);  // Increments modCount!!    //对数组进行复制,将空出的Index位置出入element,并将index后的所有数据后移一个位置。    System.arraycopy(elementData, index, elementData, index + 1,                     size - index);    //将index上的数据设置为element    elementData[index] = element;    //容量+1    size++;}

删除

public E remove(int index) {    //边界检查    rangeCheck(index);            modCount++;    //oldValue即要删除的元素    E oldValue = elementData(index);    //要复制的元素    int numMoved = size - index - 1;    if (numMoved > 0)        System.arraycopy(elementData, index+1, elementData, index,                         numMoved);    //释放最后一个元素    elementData[--size] = null; // clear to let GC do its work    return oldValue;}public boolean remove(Object o) {    //对o进行判断    if (o == null) {        for (int index = 0; index < size; index++)            if (elementData[index] == null) {                fastRemove(index);                return true;            }    } else {        for (int index = 0; index < size; index++)            if (o.equals(elementData[index])) {                fastRemove(index);                return true;            }    }    return false;}

更新

public E set(int index, E element) {    //数组扩容    rangeCheck(index);    //获取要更新的位置的数据    E oldValue = elementData(index);    //更新元素    elementData[index] = element;    return oldValue;}

总结

1.ArrayList底层是通过数组来保存数据的。默认的容量是10.

2.JDK1.8中,ArrayList扩容使用位运算newCapacity = oldCapacity + (oldCapacity >> 1)

3.ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

转载地址:http://ozuoo.baihongyu.com/

你可能感兴趣的文章
程序员的量化交易之路(19)--Cointrader之Bar实体(7)
查看>>
[Android]getevent,sendevent,input命令的使用
查看>>
开始转移精力,研究BI方向
查看>>
Android配置----adb工具的使用
查看>>
TNS-12502: TNS:listener received no CONNECT_DATA from client
查看>>
【DB2 学习】在复原过程中重定义表空间
查看>>
【mongodb系统学习之八】mongodb shell常用操作
查看>>
教你如何封装异步网络连接NSURLConnection实现带有百分比的下载
查看>>
【RAC】单节点 重启 报ORA-1105 ORA-01606
查看>>
Java IO: 流
查看>>
剑指offer系列之三:在二维数组中查找元素
查看>>
【springmvc+mybatis项目实战】杰信商贸-26.出货表修饰+下载
查看>>
【Android开发】图形图像处理技术-旋转、缩放、倾斜和平移图像
查看>>
简易Java爬虫制作
查看>>
结构模式 01-外观模式(facade)
查看>>
linux中生成考核用的GPT分区结构样例(二)
查看>>
我的友情链接
查看>>
编辑vi 查看网卡命令
查看>>
常见的内存错误及其对策
查看>>
C语言:冒泡法排序一组数,如何优化?
查看>>