ArrayList 的实现分析

来源:互联网 发布:电脑拍照软件 清晰 编辑:程序博客网 时间:2024/05/08 15:12

1. 实现原理:

内部结构是数组。

这里写图片描述

2. 特点:

查找快,改动慢。

3. 下面以增删改查为例,进行分析

3.1 增:

介绍: 先调用ensureCapacityInternal(size +1 ),确保ArryList 容器的容量可以存下当前的值,不溢出。一下为增加操作的函数代码、


size :当前存入的个数。把要存入的数据存到最后一位。

public boolean add(E e) {   ensureCapacityInternal(size + 1);  // Increments modCount!!   elementData[size++] = e;   return true;}

private void ensureCapacityInternal(int minCapacity) {    modCount++;    // overflow-conscious code    if (minCapacity - elementData.length > 0)        grow(minCapacity);}

增加的策略:
int newCapacity = oldCapacity + (oldCapacity >> 1);
oldCapacity 向右位移一位,相当于加上原来容量/2

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

带索引的增加(插入):
1. 先检查索引值是否在当前的 size (即当前存储的序列号中)
2. 确保容量
3. 增加,增加位的后一位到最后一位 存储的数据 依次向后移动一位
4. 插入到索引位置
5. size 增加

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

3.2 删除(移除):


分两种: 带索引的移除,对象的移除


索引移除:
1. 检查是否在size和0 之间,否则抛出IndexOutOfBoundsException
2. modCount++ ,用于迭代故障,只知道这些了
3. 取出要移除的元素,用于返回值
4. 计算要移动的数据个数
5. 开始移动
6. 最后一位置空

public E remove(int index) {   rangeCheck(index);   modCount++;   E oldValue = 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; }

对象移除


  1. 因为ArrayList 中是可以存储null 元素的, 先判断是否为空,因为可能出现下面情况
    String s1 = null;
    String s2 = null;
    s1.equals(s2) , 直接报空指针异常了
  2. 循环遍历,移除指定元素。
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; }

移除元素方法,使用的是 系统提供的数组复制方法,需要注意的是将 最后一位置空


private void fastRemove(int index) {  modCount++;  int numMoved = size - index - 1;  if (numMoved > 0)      System.arraycopy(elementData, index+1, elementData, index,                       numMoved);  elementData[--size] = null; // Let gc do its work}

3.3 改/查


比较简单,不做介绍

public E set(int index, E element) {     rangeCheck(index);     E oldValue = elementData(index);     elementData[index] = element;     return oldValue; }public E get(int index) {     rangeCheck(index);     return elementData(index); }

4. java 中复制方法的总结:

  1. 使用FOR循环,将数组的每个元素复制或者复制指定元素,不过效率差一点
  2. 使用clone方法,得到数组的值,而不是引用,不能复制指定元素,灵活性差一点
  3. 使用System.arraycopy(src, srcPos, dest, destPos, length)方法,推荐使用

具体代码演示:


For 循环

int[] src={1,3,5,6,7,8};int[] dest = new int[6];for(int i=0;i<6;i++) dest[i] = src[i];

2.使用clone


int[] src={1,3,5,6,7,8};int[] dest;dest=(int[]) src.clone();//使用clone创建副本,注意clone要使用强制转换

3.使用System.arraycopy

int[] src={1,3,5,6,7,8};int[] dest = new int[6];System.arraycopy(src, 0, dest, 0, 6);

System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制.

其函数原型是:
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置;
length:复制的长度.


注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,
比如:int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);
则结果为:{0,1,2,0,1,2,6};

原创粉丝点击