简述:

  • ArrayList可以理解为动态数组,与Java中的数组相比,它的容量能动态增长。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组中,因此最好能给出数组大小的预估值;
  • 容量大小也可以在程序中通过ensureCapacity(int minCapacity)方法来调整;
  • 默认第一次插入元素时创建大小为10的数组(注意,是在插入元素时,而不是new ArrayList时);
  • ArrayList继承了AbstractList,实现了List;实现了RandomAccess接口,即提供了随机访问功能;实现了Cloneable接口,覆盖了clone()方法,能被克隆;实现了Serializable接口,支持序列化;

数据结构:

  使用Object数组实现

   /**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

构造方法:

  提供了三种方式的构造器:

  1. public ArrayList() 可以构造一个空列表;
  2. public ArrayList(int initialCapacity) 构造一个指定初始容量的空列表;
  3. public ArrayList(Collection<? extends E> c) 构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列;
 /**
* Constructs an empty list with the specified initial capacity.
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

存储:

  1.set(int index, E element)

  该方法首先通过rangeCheck(index)来校验index变量是否超出数组范围,超出则抛出异常。然后取出原index位置的值作为oldValue,并将新的element放入index位置,最后返回oldValue。

   public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
return (E) elementData[index];
}

  2.add(E e)

  该方法是将指定的元素添加到列表的尾部。首先判断list是否需要扩容,然后再将元素添加到数组中。

   public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩展为原来size的1.5倍大小
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩为1.5倍大小仍不能满足需求,则直接扩为需求值(minCapacity)
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

删除:

  ArrayList提供了根据下标或者指定对象两种方式的删除功能:

  1.public E remove(int index)

     public E remove(int index) {
rangeCheck(index);
modCount++;
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;
}

  2.public boolean remove(Object o)

    public boolean remove(Object 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;
}

读取:

  1.get(int index)

  该方法会判断输入的index是否越界,然后将数组的index位置的元素返回即可。

     public E get(int index) {
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

扩容:

  扩容代码上边提到过,不再赘述。

  数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长是原容量的1.5倍。

  这种操作的代价还是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。

  如果我们可预知要保存的元素是多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。

  或者根据实际需求,在程序中通过调用ensureCapacity(int minCapacity)方法来手动调整ArrayList实例的容量,如想调整容量的增长策略,可继承ArrayList,并覆盖ensureCapacity方法。

Java中ArrayList实现原理的更多相关文章

  1. java中ArrayList 、LinkList区别

    转自:http://blog.csdn.net/wuchuanpingstone/article/details/6678653 个人建议:以下这篇文章,是从例子说明的方式,解释ArrayList.L ...

  2. JAVA中ArrayList用法

    JAVA中ArrayList用法 2011-07-20 15:02:03|  分类: 计算机专业 |  标签:java  arraylist用法  |举报|字号 订阅     Java学习过程中做题时 ...

  3. Java中ArrayList与LinkedList的区别

    Java中ArrayList与LinkedList的区别 一般大家都知道ArrayList和LinkedList的区别: 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向 ...

  4. Java中arraylist和linkedlist源代码分析与性能比較

    Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arra ...

  5. java中ArrayList 和 LinkedList 有什么区别

    转: java中ArrayList 和 LinkedList 有什么区别 ArrayList和LinkedList都实现了List接口,有以下的不同点:1.ArrayList是基于索引的数据接口,它的 ...

  6. Java中WeakHashMap实现原理深究

    一.前言 我发现Java很多开源框架都使用了WeakHashMap,刚开始没怎么去注意,只知道它里面存储的值会随时间的推移慢慢减少(在 WeakHashMap 中,当某个“弱键”不再正常使用时,会被从 ...

  7. Java中的SPI原理浅谈

    在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则& ...

  8. Java中ArrayList的自我实现

    对于ArrayList相比大家都很熟悉,它是java中最常用的集合之一.下面就给出它的自我实现的java代码. 需要说明的一点是,它是基于数组创建的.所以它在内存中是顺序存储,对于查找十分的方便. p ...

  9. Java中ArrayList相关的5道面试题

    本文参考了 <关于ArrayList的5道面试题 > 1.ArrayList的大小是如何自动增加的? 这个问题我想曾经debug过并且查看过arraylist源码的人都有印象,它的过程是: ...

随机推荐

  1. ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案 try.dot.net 的正确使用姿势 .Net NPOI 根据excel模板导出excel、直接生成excel .Net NPOI 上传excel文件、提交后台获取excel里的数据

    ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案   ASP.NET Core 从2.2版本开始,采用了一个新的名为Endpoint的路由方案,与原来的方案在使用上差别不 ...

  2. aaronyang的百度地图API之LBS云 笔记[开发准备]

    我的脚印 1.注册百度账号 先到163邮箱注册个邮箱(注册邮箱),用这个邮箱注册百度账号(注册百度),激活百度账号 2.登陆百度账号,进入 百度地图 申请为LBS开发者 2.1 注册申请为百度开发者( ...

  3. [企业化NET]Window Server 2008 R2[3]-SVN 服务端 和 客户端 基本使用

    1.  服务器基本安装即问题解决记录      √ 2.  SVN环境搭建和客户端使用 2.1  服务端 和 客户端 安装    √ 2.2  项目建立与基本使用     √ 2.3  基本冲突解决, ...

  4. CentOS 7安装Redis4.0.10

    cd /usr/local/src && wget http://download.redis.io/releases/redis-4.0.10.tar.gz && t ...

  5. Linux查看磁盘占用率及文件大小

    查看磁盘占用率: 在 df 命令中使用-h选项,以人类易读的格式输出(例如,5K,500M 及 5G) linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令 ...

  6. Spring Security教程(五):自定义过滤器从数据库从获取资源信息

    在之前的几篇security教程中,资源和所对应的权限都是在xml中进行配置的,也就在http标签中配置intercept-url,试想要是配置的对象不多,那还好,但是平常实际开发中都往往是非常多的资 ...

  7. 【Unity】7.1 Input类的方法和变量

    分类:Unity.C#.VS2015 创建日期:2016-04-21 一.简介 在Input类中,Key与物理按键对应,例如键盘.鼠标.摇杆上的按键,其映射关系无法改变,程序员可以通过按键名称或者按键 ...

  8. 深入理解Linux内核-中断和异常

    Linux内核代码查看 http://androidxref.com/ 中断:被定义位一个事件,它能改变处理器执行指令的顺序.它对应硬件(CPU.其他硬件设备)电路产生的电信号. 同步中断:指令执行时 ...

  9. html5自定义数字键盘

    原理:使用div模拟输入框,避免手机原生键盘弹出,键盘使用div模拟,点击事件使用js控制,光标闪烁使用css模拟,具体代码如下: <!doctype html> <html lan ...

  10. Android中的MVP架构分解和实现

    1.概述 传统的Android开发架构通常是MVC模式. Model:业务逻辑和实体模型 View:相应于布局文件 Controllor:相应于Activity 单独从逻辑看起来很好,与我们做Web开 ...