JAVA ArrayList详细介绍(示例)
第1部分 arraylist介绍
arraylist 是一个数组队列,相当于 动态数组。与java中的数组相比,它的容量能动态增长。它继承于abstractlist,实现了list, randomaccess, cloneable, java.io.serializable这些接口。
arraylist 继承了abstractlist,实现了list。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
arraylist 实现了randmoaccess接口,即提供了随机访问功能。randmoaccess是java中用来被list实现,为list提供快速访问功能的。在arraylist中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较list的“快速随机访问”和“通过iterator迭代器访问”的效率。
arraylist 实现了cloneable接口,即覆盖了函数clone(),能被克隆。
arraylist 实现java.io.serializable接口,这意味着arraylist支持序列化,能通过序列化去传输。
和vector不同,arraylist中的操作不是线程安全的。所以,建议在单线程中才使用arraylist,而在多线程中可以选择vector或者copyonwritearraylist。
arraylist的继承关系
arraylist与collection关系如下图:
arraylist构造函数
// 默认构造函数
arraylist()
// capacity是arraylist的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。
arraylist(int capacity)
// 创建一个包含collection的arraylist
arraylist(collection<? extends e> collection)
arraylist的api
// collection中定义的api
boolean add(e object)
boolean addall(collection<? extends e> collection)
void clear()
boolean contains(object object)
boolean containsall(collection<?> collection)
boolean equals(object object)
int hashcode()
boolean isempty()
iterator<e> iterator()
boolean remove(object object)
boolean removeall(collection<?> collection)
boolean retainall(collection<?> collection)
int size()
<t> t[] toarray(t[] array)
object[] toarray()
// abstractcollection中定义的api
void add(int location, e object)
boolean addall(int location, collection<? extends e> collection)
e get(int location)
int indexof(object object)
int lastindexof(object object)
listiterator<e> listiterator(int location)
listiterator<e> listiterator()
e remove(int location)
e set(int location, e object)
list<e> sublist(int start, int end)
// arraylist新增的api
object clone()
void ensurecapacity(int minimumcapacity)
void trimtosize()
void removerange(int fromindex, int toindex)
第2部分 arraylist源码解析
为了更了解arraylist的原理,下面对arraylist源码代码作出分析。arraylist是通过数组实现的,源码比较容易理解。
package java.util;
public class arraylist<e> extends abstractlist<e>
implements list<e>, randomaccess, cloneable, java.io.serializable
{
// 序列版本号
private static final long serialversionuid = 8683452581122892189l;
// 保存arraylist中数据的数组
private transient object[] elementdata;
// arraylist中实际数据的数量
private int size;
// arraylist带容量大小的构造函数。
public arraylist(int initialcapacity) {
super();
if (initialcapacity < 0)
throw new illegalargumentexception("illegal capacity: "+
initialcapacity);
// 新建一个数组
this.elementdata = new object[initialcapacity];
}
// arraylist构造函数。默认容量是10。
public arraylist() {
this(10);
}
// 创建一个包含collection的arraylist
public arraylist(collection<? extends e> c) {
elementdata = c.toarray();
size = elementdata.length;
// c.toarray might (incorrectly) not return object[] (see 6260652)
if (elementdata.getclass() != object[].class)
elementdata = arrays.copyof(elementdata, size, object[].class);
}
// 将当前容量值设为 =实际元素个数
public void trimtosize() {
modcount++;
int oldcapacity = elementdata.length;
if (size < oldcapacity) {
elementdata = arrays.copyof(elementdata, size);
}
}
// 确定arrarlist的容量。
// 若arraylist的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”
public void ensurecapacity(int mincapacity) {
// 将“修改统计数”+1
modcount++;
int oldcapacity = elementdata.length;
// 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
if (mincapacity > oldcapacity) {
object olddata[] = elementdata;
int newcapacity = (oldcapacity * 3)/2 + 1;
if (newcapacity < mincapacity)
newcapacity = mincapacity;
elementdata = arrays.copyof(elementdata, newcapacity);
}
}
// 添加元素e
public boolean add(e e) {
// 确定arraylist的容量大小
ensurecapacity(size + 1); // increments modcount!!
// 添加e到arraylist中
elementdata[size++] = e;
return true;
}
// 返回arraylist的实际大小
public int size() {
return size;
}
// 返回arraylist是否包含object(o)
public boolean contains(object o) {
return indexof(o) >= 0;
}
// 返回arraylist是否为空
public boolean isempty() {
return size == 0;
}
// 正向查找,返回元素的索引值
public int indexof(object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementdata[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementdata[i]))
return i;
}
return -1;
}
// 反向查找,返回元素的索引值
public int lastindexof(object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementdata[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementdata[i]))
return i;
}
return -1;
}
// 反向查找(从数组末尾向开始查找),返回元素(o)的索引值
public int lastindexof(object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementdata[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementdata[i]))
return i;
}
return -1;
}
// 返回arraylist的object数组
public object[] toarray() {
return arrays.copyof(elementdata, size);
}
// 返回arraylist的模板数组。所谓模板数组,即可以将t设为任意的数据类型
public <t> t[] toarray(t[] a) {
// 若数组a的大小 < arraylist的元素个数;
// 则新建一个t[]数组,数组大小是“arraylist的元素个数”,并将“arraylist”全部拷贝到新数组中
if (a.length < size)
return (t[]) arrays.copyof(elementdata, size, a.getclass());
// 若数组a的大小 >= arraylist的元素个数;
// 则将arraylist的全部元素都拷贝到数组a中。
system.arraycopy(elementdata, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
// 获取index位置的元素值
public e get(int index) {
rangecheck(index);
return (e) elementdata[index];
}
// 设置index位置的值为element
public e set(int index, e element) {
rangecheck(index);
e oldvalue = (e) elementdata[index];
elementdata[index] = element;
return oldvalue;
}
// 将e添加到arraylist中
public boolean add(e e) {
ensurecapacity(size + 1); // increments modcount!!
elementdata[size++] = e;
return true;
}
// 将e添加到arraylist的指定位置
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++;
}
// 删除arraylist指定位置的元素
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;
}
// 删除arraylist的指定元素
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;
}
// 快速删除第index个元素
private void fastremove(int index) {
modcount++;
int nummoved = size - index - 1;
// 从"index+1"开始,用后面的元素替换前面的元素。
if (nummoved > 0)
system.arraycopy(elementdata, index+1, elementdata, index,
nummoved);
// 将最后一个元素设为null
elementdata[--size] = null; // let gc do its work
}
// 删除元素
public boolean remove(object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementdata[index] == null) {
fastremove(index);
return true;
}
} else {
// 便利arraylist,找到“元素o”,则删除,并返回true。
for (int index = 0; index < size; index++)
if (o.equals(elementdata[index])) {
fastremove(index);
return true;
}
}
return false;
}
// 清空arraylist,将全部的元素设为null
public void clear() {
modcount++;
for (int i = 0; i < size; i++)
elementdata[i] = null;
size = 0;
}
// 将集合c追加到arraylist中
public boolean addall(collection<? extends e> c) {
object[] a = c.toarray();
int numnew = a.length;
ensurecapacity(size + numnew); // increments modcount
system.arraycopy(a, 0, elementdata, size, numnew);
size += numnew;
return numnew != 0;
}
// 从index位置开始,将集合c添加到arraylist
public boolean addall(int index, collection<? extends e> c) {
if (index > size || index < 0)
throw new indexoutofboundsexception(
"index: " + index + ", size: " + size);
object[] a = c.toarray();
int numnew = a.length;
ensurecapacity(size + numnew); // increments modcount
int nummoved = size - index;
if (nummoved > 0)
system.arraycopy(elementdata, index, elementdata, index + numnew,
nummoved);
system.arraycopy(a, 0, elementdata, index, numnew);
size += numnew;
return numnew != 0;
}
// 删除fromindex到toindex之间的全部元素。
protected void removerange(int fromindex, int toindex) {
modcount++;
int nummoved = size - toindex;
system.arraycopy(elementdata, toindex, elementdata, fromindex,
nummoved);
// let gc do its work
int newsize = size - (toindex-fromindex);
while (size != newsize)
elementdata[--size] = null;
}
private void rangecheck(int index) {
if (index >= size)
throw new indexoutofboundsexception(
"index: "+index+", size: "+size);
}
// 克隆函数
public object clone() {
try {
arraylist<e> v = (arraylist<e>) super.clone();
// 将当前arraylist的全部元素拷贝到v中
v.elementdata = arrays.copyof(elementdata, size);
v.modcount = 0;
return v;
} catch (clonenotsupportedexception e) {
// this shouldn't happen, since we are cloneable
throw new internalerror();
}
}
// java.io.serializable的写入函数
// 将arraylist的“容量,所有的元素值”都写入到输出流中
private void writeobject(java.io.objectoutputstream s)
throws java.io.ioexception{
// write out element count, and any hidden stuff
int expectedmodcount = modcount;
s.defaultwriteobject();
// 写入“数组的容量”
s.writeint(elementdata.length);
// 写入“数组的每一个元素”
for (int i=0; i<size; i++)
s.writeobject(elementdata[i]);
if (modcount != expectedmodcount) {
throw new concurrentmodificationexception();
}
}
// java.io.serializable的读取函数:根据写入方式读出
// 先将arraylist的“容量”读出,然后将“所有的元素值”读出
private void readobject(java.io.objectinputstream s)
throws java.io.ioexception, classnotfoundexception {
// read in size, and any hidden stuff
s.defaultreadobject();
// 从输入流中读取arraylist的“容量”
int arraylength = s.readint();
object[] a = elementdata = new object[arraylength];
// 从输入流中将“所有的元素值”读出
for (int i=0; i<size; i++)
a[i] = s.readobject();
}
}
总结:
(01) arraylist 实际上是通过一个数组去保存数据的。当我们构造arraylist时;若使用默认构造函数,则arraylist的默认容量大小是10。
(02) 当arraylist容量不足以容纳全部元素时,arraylist会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。
(03) arraylist的克隆函数,即是将全部元素克隆到一个数组中。
(04) arraylist实现java.io.serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
第3部分 arraylist遍历方式
arraylist支持3种遍历方式
(01) 第一种,通过迭代器遍历。即通过iterator去遍历。
integer value = null;
iterator iter = list.iterator();
while (iter.hasnext()) {
value = (integer)iter.next();
}
(02) 第二种,随机访问,通过索引值去遍历。
由于arraylist实现了randomaccess接口,它支持通过索引值去随机访问元素。
integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
value = (integer)list.get(i);
}
(03) 第三种,for循环遍历。如下:
integer value = null;
for (integer integ:list) {
value = integ;
}
下面通过一个实例,比较这3种方式的效率,实例代码(arraylistrandomaccesstest.java)如下:
import java.util.*;
import java.util.concurrent.*;
/*
* @desc arraylist遍历方式和效率的测试程序。
*
* @author skywang
*/
public class arraylistrandomaccesstest {
public static void main(string[] args) {
list list = new arraylist();
for (int i=0; i<100000; i++)
list.add(i);
//israndomaccesssupported(list);
iteratorthroughrandomaccess(list) ;
iteratorthroughiterator(list) ;
iteratorthroughfor2(list) ;
}
private static void israndomaccesssupported(list list) {
if (list instanceof randomaccess) {
system.out.println("randomaccess implemented!");
} else {
system.out.println("randomaccess not implemented!");
}
}
public static void iteratorthroughrandomaccess(list list) {
long starttime;
long endtime;
starttime = system.currenttimemillis();
for (int i=0; i<list.size(); i++) {
list.get(i);
}
endtime = system.currenttimemillis();
long interval = endtime - starttime;
system.out.println("iteratorthroughrandomaccess:" + interval+" ms");
}
public static void iteratorthroughiterator(list list) {
long starttime;
long endtime;
starttime = system.currenttimemillis();
for(iterator iter = list.iterator(); iter.hasnext(); ) {
iter.next();
}
endtime = system.currenttimemillis();
long interval = endtime - starttime;
system.out.println("iteratorthroughiterator:" + interval+" ms");
}
public static void iteratorthroughfor2(list list) {
long starttime;
long endtime;
starttime = system.currenttimemillis();
for(object obj:list)
endtime = system.currenttimemillis();
long interval = endtime - starttime;
system.out.println("iteratorthroughfor2:" + interval+" ms");
}
}
运行结果:
iteratorthroughrandomaccess:3 ms
iteratorthroughiterator:8 ms
iteratorthroughfor2:5 ms
由此可见,遍历arraylist时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!
第4部分 toarray()异常
当我们调用arraylist中的 toarray(),可能遇到过抛出“java.lang.classcastexception”异常的情况。下面我们说说这是怎么回事。
arraylist提供了2个toarray()函数:
object[] toarray()
<t> t[] toarray(t[] contents)
调用 toarray() 函数会抛出“java.lang.classcastexception”异常,但是调用 toarray(t[] contents) 能正常返回 t[]。
toarray() 会抛出异常是因为 toarray() 返回的是 object[] 数组,将 object[] 转换为其它类型(如如,将object[]转换为的integer[])则会抛出“java.lang.classcastexception”异常,因为java不支持向下转型。具体的可以参考前面arraylist.java的源码介绍部分的toarray()。
解决该问题的办法是调用 <t> t[] toarray(t[] contents) , 而不是 object[] toarray()。
调用 toarray(t[] contents) 返回t[]的可以通过以下几种方式实现。
// toarray(t[] contents)调用方式一
public static integer[] vectortoarray1(arraylist<integer> v) {
integer[] newtext = new integer[v.size()];
v.toarray(newtext);
return newtext;
}
// toarray(t[] contents)调用方式二。最常用!
public static integer[] vectortoarray2(arraylist<integer> v) {
integer[] newtext = (integer[])v.toarray(new integer[0]);
return newtext;
}
// toarray(t[] contents)调用方式三
public static integer[] vectortoarray3(arraylist<integer> v) {
integer[] newtext = new integer[v.size()];
integer[] newstrings = (integer[])v.toarray(newtext);
return newstrings;
}
第5部分 arraylist示例
本文通过一个实例(arraylisttest.java),介绍 arraylist 的常用api。
import java.util.*;
/*
* @desc arraylist常用api的测试程序
* @author skywang
* @email kuiwu-wang@163.com
*/
public class arraylisttest {
public static void main(string[] args) {
// 创建arraylist
arraylist list = new arraylist();
// 将“”
list.add("1");
list.add("2");
list.add("3");
list.add("4");
// 将下面的元素添加到第1个位置
list.add(0, "5");
// 获取第1个元素
system.out.println("the first element is: "+ list.get(0));
// 删除“3”
list.remove("3");
// 获取arraylist的大小
system.out.println("arraylist size=: "+ list.size());
// 判断list中是否包含"3"
system.out.println("arraylist contains 3 is: "+ list.contains(3));
// 设置第2个元素为10
list.set(1, "10");
// 通过iterator遍历arraylist
for(iterator iter = list.iterator(); iter.hasnext(); ) {
system.out.println("next is: "+ iter.next());
}
// 将arraylist转换为数组
string[] arr = (string[])list.toarray(new string[0]);
for (string str:arr)
system.out.println("str: "+ str);
// 清空arraylist
list.clear();
// 判断arraylist是否为空
system.out.println("arraylist is empty: "+ list.isempty());
}
}