JDK8集合类源码解析 - ArrayList

ArrayList主要要注意以下几点:

1构造方法

2添加add(E e) 

3 获取 get(int index)

4 删除 remove(int index)    ,   remove(Object o)

5 判断是否存在 contains(Object o)

6 遍历

======================================

底层采用数组实现。

1构造方法

有三个 分别是 指定数组大小;不指定(创建一个空的,添加元素的时候再扩容);从一个集合创建

 

这里顺便说下集合的继承关系

 Collection

    |--List

       |--ArrayList

       |--Vector

       |--LinkedList

    |--Set

       |--HashSet

       |--TreeSet

2添加add(E e) 

 

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 先判断容量够不够
        //添加到末尾
        elementData[size++] = e;
        return true;
}
 private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) { //空就创建一个长度为10的数组
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++; //操作计数+1 用于在遍历的时候判断是否有添加或者删除操作
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//扩容
    }

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//变成原来的1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新容量 MAX_ARRAY_SIZE还大 那么新容量就设置为Integer.MAX_VALUE
            newCapacity = hugeCapacity(minCapacity);
        //复制数据
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

 

  

3 获取 get(int index)

 

  public E get(int index) {

        rangeCheck(index); //看数组是否越界

        return elementData(index);

    }

4 删除 remove(int index)    ,   remove(Object o)

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; // 方便gc回收
        return oldValue;
}

  

 remove(Object o) 先遍历找到该元素,然后在删除 ,删除方法和上面的方法类似,需要移动数组(如果不是最后一个元素的话)

5 判断是否存在 contains(Object o)

//遍历 找到了就返回下标 不然返回 -1
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    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;
    }

6遍历

 int cursor;       // 遍历标志位
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
 注意两点:       1遍历的时候 如果要删除元素 要使用Iterator
                2只有调用了next才能调用remove

  

最佳实践

1如果能够预知集合大小,创建的时候最好使用指定大小的构造函数,能够提高性能(没有了扩容)

2线程不安全,多线程环境建议使用CopyOnWriteArrayList

3遍历集合 如果要删除元素 要使用Iterator

4底层基于数值实现,增删慢 获取快(仅限于下标方式)

 

posted on 2017-06-27 18:04  一只小蜗牛12138  阅读(125)  评论(0编辑  收藏  举报

导航