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

作者:然则 时间:2023-07-22 02:32:49 

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()抛出异常时执行。

标签:Java,ArrayList
0
投稿

猜你喜欢

  • Java实现斗地主最简代码实例

    2023-07-11 18:40:02
  • SpringBoot利用注解来实现Redis分布式锁

    2022-02-13 16:57:36
  • Android WindowManger实现桌面悬浮窗功能

    2023-08-01 02:16:10
  • Java Lambda表达式超详细介绍

    2021-09-25 03:16:43
  • IDEA 热部署设置(JRebel插件激活)

    2021-08-25 08:14:39
  • C#实现导入CSV文件到Excel工作簿的方法

    2022-09-13 12:24:02
  • 在Android中使用WebSocket实现消息通信的方法详解

    2022-06-10 06:26:18
  • Java通过Scanner了解if...else if语句

    2023-11-29 04:28:44
  • SpringBoot结合Redis配置工具类实现动态切换库

    2022-04-15 14:14:13
  • C# Winform按钮中图片实现左图右字的效果实例

    2022-05-01 12:51:41
  • Mybatis获取参数值和查询功能的案例详解

    2023-02-09 13:25:14
  • Android仿Iphone屏幕底部弹出半透明PopupWindow效果

    2023-08-17 06:14:43
  • C#实现的MD5加密功能与用法示例

    2023-06-11 09:08:21
  • Java反射通过Getter方法获取对象VO的属性值过程解析

    2023-04-11 06:11:33
  • Android Flutter实现GIF动画效果的方法详解

    2023-02-06 02:46:37
  • Android MotionEvent中getX()和getRawX()的区别实例详解

    2023-01-24 22:06:42
  • springboot如何将http转https

    2023-02-27 17:10:45
  • SpringBoot配置SSL同时支持http和https访问实现

    2023-04-25 19:42:45
  • Android开发技巧之像QQ一样输入文字和表情图像

    2022-06-26 23:41:34
  • 不可不知的Android strings.xml那些事

    2022-06-04 00:14:05
  • asp之家 软件编程 m.aspxhome.com