ArrayList底层(二)

有参构造:

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

这个看上去就没这么复杂了,初始化数组都给定了长度,不会出现无参构造那种想要一个长度10的数组却给了个长度为0的数组。
if分支对数组索引划分三个区间:
1.initialCapacity>0,将数组容量设为人为定义的值
2.initialCapacity==0,将数组容量设为默认值:10
3.initialCapacity<=,报非法数据异常,并提示输入的<0的数字。

有参add方法:

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

这个方法的意图就是插入一个元素到指定的所以位置。

1.rangeCheckForAdd()

我们先看add中的rangeCheckForAdd方法:

    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

只要输入的所以位置比元素个数大或者索引小于0就抛一个Index越界异常。
可能有人会好奇为什么是index>size
问:假设当前有6个元素,那你输入一个7,这样可以插入成吗?
答:当然不可以

int a [] = new int[10];
int size=0;
a[size++]=99;

就用三行解释,a[0]=99,a[1]=0
有1个元素,不能插在a[2]的位置,中间的a[1]就浪费了。
有6个元素,不能插在a[7]的位置。

2.ensureCapacityInternal()

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

这个方法上篇帖子有解释:看看要不要扩容。

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

需要扩容就grow()进行扩容。

3.System.arraycopy()

    //src      原数组
    //src      原数组开始位置
    //dest     目标数组
    //destPos  目标数组开始位置
    //length   要复制的长度
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

这个方法在final类System中,是一个java调用,不是接口。我们看上去类似一个抽象方法,它没有方法体,实则它有实体,只不过它的实体不再是java代码。
那就直接挖到我们能看懂的最底层,一部一部找下去,直到C语言库函数中的memmoe方法:

void *memmove(void *dest, const void *src, size_t count){

     assert( (dest!=NULL)&&(src!=NULL) );

      char *tmp_dest=(char*)dest;
      char *tmp_src=(char*)src;
      
      if( tmp_dest<tmp_src) {
           // 如果没有重叠区域
           while(count--)
                 *tmp_dest++=*tmp_src;
      } else {
           // 如果有重叠区域
          tmp_dest+=count-1;
          tmp_src+=count-1;
          while(count--)
               *--tmp_dest=*--tmp_src;
     }

      return dest;
}

函数功能:将字符串src中的前n个字节拷贝到dest中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值