欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JAVA ArrayList详细介绍(示例)

程序员文章站 2024-02-13 10:35:40
第1部分 arraylist介绍arraylist 是一个数组队列,相当于 动态数组。与java中的数组相比,它的容量能动态增长。它继承于abstractlist,实现了l...

第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的继承关系
JAVA ArrayList详细介绍(示例)
arraylist与collection关系如下图:
JAVA ArrayList详细介绍(示例)
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());
    }
}