Java中ArrayList实现原理
简述:
- 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
构造方法:
提供了三种方式的构造器:
- public ArrayList() 可以构造一个空列表;
- public ArrayList(int initialCapacity) 构造一个指定初始容量的空列表;
- 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实现原理的更多相关文章
- java中ArrayList 、LinkList区别
转自:http://blog.csdn.net/wuchuanpingstone/article/details/6678653 个人建议:以下这篇文章,是从例子说明的方式,解释ArrayList.L ...
- JAVA中ArrayList用法
JAVA中ArrayList用法 2011-07-20 15:02:03| 分类: 计算机专业 | 标签:java arraylist用法 |举报|字号 订阅 Java学习过程中做题时 ...
- Java中ArrayList与LinkedList的区别
Java中ArrayList与LinkedList的区别 一般大家都知道ArrayList和LinkedList的区别: 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向 ...
- Java中arraylist和linkedlist源代码分析与性能比較
Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arra ...
- java中ArrayList 和 LinkedList 有什么区别
转: java中ArrayList 和 LinkedList 有什么区别 ArrayList和LinkedList都实现了List接口,有以下的不同点:1.ArrayList是基于索引的数据接口,它的 ...
- Java中WeakHashMap实现原理深究
一.前言 我发现Java很多开源框架都使用了WeakHashMap,刚开始没怎么去注意,只知道它里面存储的值会随时间的推移慢慢减少(在 WeakHashMap 中,当某个“弱键”不再正常使用时,会被从 ...
- Java中的SPI原理浅谈
在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则& ...
- Java中ArrayList的自我实现
对于ArrayList相比大家都很熟悉,它是java中最常用的集合之一.下面就给出它的自我实现的java代码. 需要说明的一点是,它是基于数组创建的.所以它在内存中是顺序存储,对于查找十分的方便. p ...
- Java中ArrayList相关的5道面试题
本文参考了 <关于ArrayList的5道面试题 > 1.ArrayList的大小是如何自动增加的? 这个问题我想曾经debug过并且查看过arraylist源码的人都有印象,它的过程是: ...
随机推荐
- “The operation cannot be completed because the DbContext has been disposed” exception with lazy load disabled
http://stackoverflow.com/questions/18261732/the-operation-cannot-be-completed-because-the-dbcontext- ...
- 还没被玩坏的robobrowser(8)——robobrowser的实现原理
背景 学习使用工具实际上不难,不过我们应该通过阅读工具源码来提升自己的水平. 多读代码,读好代码.很不错,robobrowser的代码简单易懂,值得学习. 预备知识 源码地址 一起其实是从browse ...
- 第2章 Python基础-字符编码&数据类型 购物车&多级菜单 作业
作业 一.三级菜单 数据结构: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, ...
- 个人用户使用genymotion 模拟器
genymotion android模拟器速度快,比较好用.对公司使用的是要收费的,但是对个人使用还是免费的,所以个人用户还可以继续使用.使用方法 1.注册账号,填写用户名.邮箱.密码.公司类型(选g ...
- Java 在给定路径上创建文件,所在文件夹不存在时,如何正确创建。
String strPath = "E:\\a\\aa\\aaa.txt"; File file = new File(strPath); if(!file.exists())){ ...
- FIR特性及仿真实现_01
作者:桂. 时间:2018-02-05 19:01:21 链接:http://www.cnblogs.com/xingshansi/p/8419007.html 前言 本文主要记录FIR(finit ...
- MySQL中NULL与空字符串
一些刚刚接触MySQL的孩子,经常会错误的认为NULL与空字符串’ ’是相同的.这看似是一件不重要的事情,但是在MySQL中,这两者是完全不同的.NULL是指没有值,而”则表示值是存在的,只不过是个 ...
- 【Objective-C】OC中KVO的基本概念和使用方法
基本概念: 键值观察是一种使用获取其他对象的特定属性变化的通知机制. 控制器层的绑定技术就是严重依赖键值观察获得模型层和控制器层的变化通知的. 对于不依赖控制器层类的应用程序,键值观察提供了一种简化的 ...
- webBrowser获取取Cookie不全的解决方法
//取当前webBrowser登录后的Cookie值 [DllImport("wininet.dll", CharSet = CharSet.Auto, Set ...
- 第九章·词典
第九章·词典 散列:原理 散列是一种赖以高效组织数据并实现相关算法的重要思想. 这样的思想背后的原理却非常直观.简单. 上图是IBM公司和联想公司的服务电话号码,能够看到这样的号码是由数字和字母共同组 ...