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

Java中ArrayList类的用法与源码完全解析

程序员文章站 2024-03-11 10:06:01
system.collections.arraylist类是一个特殊的数组。通过添加和删除元素,就可以动态改变数组的长度。 一.优点 1. 支持自动改变大小的功能 2...

system.collections.arraylist类是一个特殊的数组。通过添加和删除元素,就可以动态改变数组的长度。

一.优点
1. 支持自动改变大小的功能
2. 可以灵活的插入元素
3. 可以灵活的删除元素

二.局限性
跟一般的数组比起来,速度上差些

三.添加元素
1.publicvirtualintadd(objectvalue);
将对象添加到arraylist的结尾处

arraylist alist = new arraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");

内容为

abcde

2.publicvirtualvoidinsert(intindex,objectvalue);
将元素插入arraylist的指定索引处

arraylist alist = new arraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.insert(0,"aa");

结果为

aaabcde

3.publicvirtualvoidinsertrange(intindex,icollectionc);
将集合中的某个元素插入arraylist的指定索引处

arraylist alist = new arraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
arraylist list2 = newarraylist();
list2.add("tt");
list2.add("ttt");
alist.insertrange(2,list2);

结果为

abtttttcde

四.删除
1. publicvirtualvoidremove(objectobj);
从arraylist中移除特定对象的第一个匹配项,注意是第一个

arraylist alist = new arraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.remove("a");

结果为

bcde

2. publicvirtualvoidremoveat(intindex);
移除arraylist的指定索引处的元素

alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.removeat(0);

结果为

bcde

3.publicvirtualvoidremoverange(intindex,intcount);
从arraylist中移除一定范围的元素。index表示索引,count表示从索引处开始的数目

alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.removerange(1,3);

结果为

复制代码 代码如下:
ae

4.publicvirtualvoidclear();
从arraylist中移除所有元素。

五.排序
1. publicvirtualvoidsort();
对arraylist或它的一部分中的元素进行排序。

arraylistalist=newarraylist();
alist.add("e");
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
dropdownlist1.datasource=alist;//dropdownlistdropdownlist1;
dropdownlist1.databind();

结果为

eabcd
arraylistalist=newarraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.sort();//排序
dropdownlist1.datasource=alist;//dropdownlistdropdownlist1;
dropdownlist1.databind();

结果为

abcde

2.publicvirtualvoidreverse();
将arraylist或它的一部分中元素的顺序反转。

arraylistalist=newarraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");
alist.reverse();//反转
dropdownlist1.datasource=alist;//dropdownlistdropdownlist1;
dropdownlist1.databind();

结果为

edcba

六.查找
1.publicvirtualintindexof(object);
2. publicvirtualintindexof(object,int);
3. publicvirtualintindexof(object,int,int);
    返回arraylist或它的一部分中某个值的第一个匹配项的从零开始的索引。没找到返回-1。

  arraylist alist = new arraylist();
  alist.add("a");
  alist.add("b");
  alist.add("c");
  alist.add("d");
  alist.add("e");
  intnindex=alist.indexof(“a”);//1
  nindex=alist.indexof(“p”);//没找到,-1

4.publicvirtualintlastindexof(object);
5.publicvirtualintlastindexof(object,int);
6.publicvirtualintlastindexof(object,int,int);
    返回arraylist或它的一部分中某个值的最后一个匹配项的从零开始的索引。

  arraylist alist = new arraylist();
  alist.add("a");
  alist.add("b");
  alist.add("a");//同0
  alist.add("d");
  alist.add("e");
  intnindex=alist.lastindexof("a");//值为2而不是0

7. publicvirtualboolcontains(objectitem);
    确定某个元素是否在arraylist中。包含返回true,否则返回false

七.其他
1.publicvirtualintcapacity{get;set;}
获取或设置arraylist可包含的元素数。
2.publicvirtualintcount{get;}
获取arraylist中实际包含的元素数。
capacity是arraylist可以存储的元素数。count是arraylist中实际包含的元素数。capacity总是大于或等于count。如果在添加元素时,count超过capacity,则该列表的容量会通过自动重新分配内部数组加倍。
如果capacity的值显式设置,则内部数组也需要重新分配以容纳指定的容量。如果capacity被显式设置为0,则公共语言运行库将其设置为默认容量。默认容量为16。
在调用clear后,count为0,而此时capacity切是默认容量16,而不是0
3.publicvirtualvoidtrimtosize();
将容量设置为arraylist中元素的实际数量。
如果不向列表中添加新元素,则此方法可用于最小化列表的内存系统开销。
若要完全清除列表中的所有元素,请在调用trimtosize之前调用clear方法。截去空arraylist会将arraylist的容量设置为默认容量,而不是零。

arraylist alist = new arraylist();
alist.add("a");
alist.add("b");
alist.add("c");
alist.add("d");
alist.add("e");//count=5,capacity=16,
alist.trimtosize();//count=capacity=5;

八.源码分析
list 接口的一个实现类,内部是用一个数组存储元素值,相当于一个可变大小的数组。

1.签名

public class arraylist<e>
extends abstractlist<e>
implements list<e>, randomaccess, cloneable, serializable

可以看到arraylist继承了abstractlist抽象类,它实现了list接口的大多数方法。如果要实现一个不可变的list,只要继承这个类并且实现get(int)和size方法。如果要实现可变的list,需要覆盖set(int, e)。另外,如果list的大小是可变的,还要覆盖add(int, e)和remove()方法。

2.构造器
arraylist提供了三个构造器:

arraylist()
arraylist(collection<? extends e> c)
arraylist(int initialcapacity)

collection接口约定,每个集合类应该提供两个”标准”构造器,一个是无参数的构造器(上面第一个),另外一个是拥有单个参数(类型为collettion)的构造器(上面第二个)。arraylist还提供了第三个构造器,其接受一个int值,用于设置arrayli的初始大小(默认大小为10)。

3.相关方法

trimtosize
public void trimtosize() {
    modcount++;
    int oldcapacity = elementdata.length;
    if (size < oldcapacity) {
      elementdata = arrays.copyof(elementdata, size);
    }
  }

用于把arraylist的容量缩减到当前实际大小,减少存储容量。其中的变量modcount由abstraclist继承而来,记录list发生结构化修改(structurally modified)的次数。elementdata中实际存储了arraylist的元素,在arraylist中声明为:private transient object[] elementdata;变量size是arraylist的元素数量,当size < oldcapacity时,调用arrays.copyof方法实现缩减。

4.indexof 和 lasindexof

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;
  }

这两个方法返回指定元素的下标,要区分参数是否为null。lastindexof和indexof类似,只不过是从后往前搜索。

5.ensurecapacity

public void ensurecapacity(int mincapacity) {
    if (mincapacity > 0)
      ensurecapacityinternal(mincapacity);
  }
private void ensurecapacityinternal(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;
    int newcapacity = oldcapacity + (oldcapacity >> 1);
    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);
  }

这个方法可以确保arraylist的大小

6.add 和 addall

public void add(int index, e element) {
    rangecheckforadd(index);

    ensurecapacityinternal(size + 1); // increments modcount!!
    system.arraycopy(elementdata, index, elementdata, index + 1,
             size - index);
    elementdata[index] = element;
    size++;
  }

add(int index, e element)向指定位置添加元素,首先调用rangecheckforadd检查index是否有效,如果index > size || index < 0将抛出异常。然后确保容量加1,调用system.arraycopy把从index开始的元素往后移动一个位置。最后把index处的值设置为添加的元素。还有一个重载的add(e e)方法是直接把元素添加到末尾。
addall(collection<? extends e> c)和addall(int index, collection<? extends e> c)则分别是向末尾和指定位置添加collection中的所有元素。

7.remove 和 removeall

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;
  }

remove(object o)方法删除指定的元素。首先是查找元素位置,然后调用fastremove(index)删除,其代码如下:

private void fastremove(int index) {
    modcount++;
    int nummoved = size - index - 1;
    if (nummoved > 0)
      //把index+1往后的元素都往前移动一个位置
      system.arraycopy(elementdata, index+1, elementdata, index,
               nummoved);
    elementdata[--size] = null; // let gc do its work
  }

重载的remove(int index)方法用于删除指定位置的元素。removerange(int fromindex, int toindex)用于删除指定位置之间的所有元素。
removeall(collection<?> c)和retainall(collection<?> c)代码如下:

public boolean removeall(collection<?> c) {
    objects.requirenonnull(c);
    return batchremove(c, false);
  }
public boolean retainall(collection<?> c) {
    objects.requirenonnull(c);
    return batchremove(c, true);
  }

它们都是通过调用batchremove方法实现的,其代码如下:

private boolean batchremove(collection<?> c, boolean complement) {
    final object[] elementdata = this.elementdata;
    int r = 0, w = 0;
    boolean modified = false;
    try {
      for (; r < size; r++)
        if (c.contains(elementdata[r]) == complement)
          elementdata[w++] = elementdata[r];
    } finally {
      // preserve behavioral compatibility with abstractcollection,
      // even if c.contains() throws.
      if (r != size) {
        system.arraycopy(elementdata, r,
                 elementdata, w,
                 size - r);
        w += size - r;
      }
      if (w != size) {
        // clear to let gc do its work
        for (int i = w; i < size; i++)
          elementdata[i] = null;
        modcount += size - w;
        size = w;
        modified = true;
      }
    }
    return modified;
  }

这个方法有两个参数,第一个是操作的collection,第二个是一个布尔值,通过设置为true或false来选择是removeall还是retainall。try里面的语句是把留下来的放在0到w之间,然后在finally中第二个if处理w之后的空间,第一个是在c.contains()抛出异常时执行。