ArrayList详解和使用示例_动力节点Java学院整理
第1部分 arraylist介绍
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() // 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的继承关系
java.lang.object java.util.abstractcollection<e> java.util.abstractlist<e> java.util.arraylist<e> public class arraylist<e> extends abstractlist<e> implements list<e>, randomaccess, cloneable, java.io.serializable {}
arraylist与collection关系如下图:
arraylist包含了两个重要的对象:elementdata 和 size。
(1) elementdata 是"object[]类型的数组",它保存了添加到arraylist中的元素。实际上,elementdata是个动态数组,我们能通过构造函数 arraylist(int initialcapacity)来执行它的初始容量为initialcapacity;如果通过不含参数的构造函数arraylist()来创建arraylist,则elementdata的容量默认是10。elementdata数组的大小会根据arraylist容量的增长而动态的增长,具体的增长方式,请参考源码分析中的ensurecapacity()函数。
(2) size 则是动态数组的实际大小。
第3部分 arraylist源码解析(基于jdk1.6.0_45)
为了更了解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(); } // 创建一个包含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 + ); // 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+, 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+, 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 = ; 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的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
第4部分 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; }
由此可见,遍历arraylist时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!
第5部分 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; }
第6部分 arraylist示例
本文通过一个实例(arraylisttest.java),介绍 arraylist 中常用api的用法。
import java.util.*; /* * @desc arraylist常用api的测试程序 * * */ 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[]); for (string str:arr) system.out.println("str: "+ str); // 清空arraylist list.clear(); // 判断arraylist是否为空 system.out.println("arraylist is empty: "+ list.isempty()); } }
运行结果:
the first element is: 5 arraylist size=: 4 arraylist contains 3 is: false next is: 5 next is: 10 next is: 2 next is: 4 str: 5 str: 10 str: 2 str: 4 arraylist is empty: true
以上所述是小编给大家介绍的arraylist详解和使用示例_动力节点java学院整理,希望对大家有所帮助
推荐阅读
-
ArrayList详解和使用示例_动力节点Java学院整理
-
ByteArrayOutputStream简介和使用_动力节点Java学院整理
-
Java中的FileInputStream 和 FileOutputStream 介绍_动力节点Java学院整理
-
PipedWriter和PipedReader源码分析_动力节点Java学院整理
-
Java 中的HashMap详解和使用示例_动力节点Java学院整理
-
Java中的HashSet详解和使用示例_动力节点Java学院整理
-
Java序列化和反序列化_动力节点Java学院整理
-
interrupt()和线程终止方式_动力节点Java学院整理
-
Java interrupt()方法使用注意_动力节点Java学院整理
-
ObjectInputStream 和 ObjectOutputStream 介绍_动力节点Java学院整理