ArrayList 的实现分析

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值