ArrayList 解析

一.简介

继承图

-List
    --ArrayList 

ArrayList 是一个由数组实现的列表,可以重复,不同步,可以存null;实现了List 的CURL 操作,且可以自动扩容.今天我们对该类的源码进行解析.

二.构造函数

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 transient Object[] elementData; 
 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  //其实就是以静态方法区的一个数组当成缓存,从而避免创建多个数组  

image

三.CRUD 的操作

3.1 add 操作
 /**
     * Appends the specified element to the end of this list.
     *翻译:增加一个特点的元素在list的最后
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 动态的堆内部的数组进行扩容
        elementData[size++] = e;//把元素插在最后面
        return true;
    }

扩容

   private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//常规情况初始为10
        }

        ensureExplicitCapacity(minCapacity);
    }

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//mod 表示修改次数

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//很明显,这里操作就是容量不足的时候,进行增加一个新的容器,并做复制操作
    }

  /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     * 翻译: 增加数组的容积,确保 能存放所有的元素
     * 具体的策略如下:
     * 1.获得原容积的1.5倍的大小,与传进来的最小容量对比,选择比较小的
     * 2.假如超过最大容量则用最大容量
     * 3.然后做复制数据到新的容器
     * @param minCapacity the desired minimum capacity
     */
    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 对象创建后,内部数组的初始长度未0,内部数组指向一个静态缓存数组
  • 首次添加数据时,会扩容到10,或者自己指定的长度
  • 每次扩容,都会扩大原来的1.5倍,或者自己指定的长度
  • 每次扩容,实际都是新创建一个数组然后再把数据复制到新数组中然后返回
  • 超过长度(Integer.MAX_VALUE - 8)就不会扩容了
  • 最小指定的长度为负数,会抛异常
  • size 表示的是逻辑容量而不是内部数组的实际容量
  • modCount 代表修改的次数
3.1 get 操作
  /**
     * Returns the element at the specified position in this list.
     * 翻译:返回指定位置(position)的元素
     */
     public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    //检测index是否合法
    private void rangeCheck(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
   E elementData(int index) {
        return (E) elementData[index];
    }
3.2 set 操作:存放并返回对应的元素

“`java
public E set(int index, E element) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    E oldValue = (E) elementData[index];
    elementData[index] = element;
    return oldValue;
}

3.2 remove 操作

“`java
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* 翻译:移除列表中特定位置的元素,将任何后续元素向左移动(从他们中减去一个元素)
*/
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; // clear to let GC do its work

    return oldValue;
}

### 3.3 add &addAll
```java
public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
// 注意:就算是增加多个元素 modCount 就 ++ 而已
 public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }




<div class="se-preview-section-delimiter"></div>

3.4 clear

public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }


### 3.4 clear: 容积不变,元素清空,size置零

```java
public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }




<div class="se-preview-section-delimiter"></div>

四.SubList

ArrayList中,存在一个内部类SubList.他与ArrayList 一样继承AbstractList.同时有crud 操作
我们发现,parent就是对原始的list的引用,SubList 的crud 就是对ArrayList 的crud 操作

4.1.SubList的妙用
list.subList(100,200).clear();


### 四.SubList
ArrayList中,存在一个内部类SubList.他与ArrayList 一样继承AbstractList.同时有crud 操作
我们发现,parent就是对原始的list的引用,SubList 的crud 就是对ArrayList 的crud 操作

####  4.1.SubList的妙用

list.subList(100,200).clear();

直接删除一段数据(100-199),而不是for循环,
其实就是迭代器删除的

protected void removeRange(int fromIndex, int toIndex) {
ListIterator it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i




#### 六.序列化
内部数组用transient 修饰,表示不被序列化,但是我们的数据都是放在数组中的,数据不序列化,我们持久化了有什么用呢?因为ElementData 不一定满的,没有用上的空间我们并不想再耗时间去序列化.但有存储数据的空间我们还是有序列化的,隐藏,java重写了writeObject 方法,以实现局部序列化

private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

“`

七:总结
1.Arraylist 继承List,内部维护一个一维数组
2.使用1.5倍的方式扩容;
3.使用System.arraycopy()进行扩容的赋值
4.首次默认扩容10;
5.不同步,查询快,插入删除慢;
6.内部类SubList 最终调用也是ArrayList
7.ArrayList 重写了writeObject 方法优化数组的序列化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值