zoukankan      html  css  js  c++  java
  • List集合之ArrayList

    一、初步了解ArrayList

             ArrayList是集合的一种实现,实现了接口List,List接口继承了Collection接口。Collection是所有集合类的父类。

             ArrayList底层是用数组实现的存储。

             特点:查询效率高,增删效率低,线程不安全。

    二、继承结构

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    继承:AbstractList。
    实现:List、RandomAccess、Cloneable、Serializable。

    三、源码分析

    一、扩容的原理add()

    数组长度有限,而ArrayList是可以存放任意数量的对象,长度不受限制,他是怎样实现的呢?

    第一步:add(E e)

    1 public boolean add(E e) {
    2         // 这句代码是关键,涉及首次添加元素的elementData的初始化和扩容,加入元素前检查容量是否足够
    3         ensureCapacityInternal(size + 1);  // Increments modCount!!
    4         // 元素被添加在数组末尾
    5         // 没有做null检查,元素可以为null
    6         elementData[size++] = e;
    7         return true;
    8     }

    第二步:ensureCapacityInternal(size + 1);

     1 private void ensureCapacityInternal(int minCapacity) {
     2         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
     3     }
     4 
     5 private void ensureExplicitCapacity(int minCapacity) {         //检查并确保容量
     6         modCount++;
     7 
     8         // overflow-conscious code
     9         if (minCapacity - elementData.length > 0)      //如果添加元素后大于当前数组的长度,则进行扩容
    10             grow(minCapacity);       //扩容方法
    11     }

    第三步:grow(minCapacity);

     1 private void grow(int minCapacity) {
     2         // overflow-conscious code
     3         int oldCapacity = elementData.length;
     4         // 扩容后新的elementData大小:将数组长度增加到原来的一半
     5         int newCapacity = oldCapacity + (oldCapacity >> 1);
     6         // 扩容后仍然不满足需要,则赋值为minCapacity
     7         if (newCapacity - minCapacity < 0)
     8             newCapacity = minCapacity;
     9         // 扩容后超出允许的最大数组大小
    10         if (newCapacity - MAX_ARRAY_SIZE > 0)
    11             // 确保newCapacity最大只能为Integer.MAX_VALUE
    12             newCapacity = hugeCapacity(minCapacity);
    13         // 分配新数组,拷贝旧数据
    14         elementData = Arrays.copyOf(elementData, newCapacity);
    15     }

    以上分析可知:

    1. 如果使用了默认的构造函数,那么elementData初始化大小为10.
    2. 正常情况下,每次扩容后的elementData新大小=1.5倍旧大小。
    3. elementData最大值只能为Integer.MAX_VALUE。

    2、add(int index, E element)

     1 public void add(int index, E element) {
     2         // 首先检查inde是否合法
     3         rangeCheckForAdd(index);
     4 
     5         ensureCapacityInternal(size + 1);  // 看elementData的长度是否做够,不够扩容
     6 
     7         // 这个地方主要为了将index位置的数据及其后的数据后移一位
     8         System.arraycopy(elementData, index, elementData, index + 1,
     9                          size - index);
    10         // 将元素赋值给数组index处
    11         elementData[index] = element;
    12         size++;
    13     }

    二、remove(int index)删除列表中指定位置的元素

     1     public E remove(int index) {
     2         // 检查索引
     3         rangeCheck(index);
     4 
     5         modCount++;
     6         // 获取旧的元素
     7         E oldValue = elementData(index);
     8 
     9         // 计算需要移动的元素个数
    10         int numMoved = size - index - 1;
    11         if (numMoved > 0)
    12             // 通过拷贝完成元素的删除
    13             System.arraycopy(elementData, index+1, elementData, index,
    14                              numMoved);
    15         // 赋值为null,保证可以被GC回收
    16         elementData[--size] = null; // clear to let GC do its work
    17 
    18         // 返回旧的数据
    19         return oldValue;
    20     }

    remove(Object o)删除列表中第一个出现O的元素

     1     // 删除元素。
     2     // 只会删除第一个出现的元素。
     3     public boolean remove(Object o) {
     4         if (o == null) {
     5             // for循环遍历元素。找出待删除元素的index
     6             for (int index = 0; index < size; index++)
     7                 if (elementData[index] == null) {
     8                     fastRemove(index);
     9                     // 此处导致只会删除第一个找到的相等元素
    10                     return true;
    11                 }
    12         } else {
    13             // for循环遍历元素。找出待删除元素的index
    14             for (int index = 0; index < size; index++)
    15                 if (o.equals(elementData[index])) {
    16                     fastRemove(index);
    17                     // 此处导致只会删除第一个找到的相等元素
    18                     return true;
    19                 }
    20         }
    21         return false;
    22     }
    23 
    24     // 该方法与remove(int index)基本相同
    25     private void fastRemove(int index) {
    26         modCount++;
    27         int numMoved = size - index - 1;
    28         if (numMoved > 0)
    29             System.arraycopy(elementData, index+1, elementData, index,
    30                              numMoved);
    31         elementData[--size] = null; // clear to let GC do its work
    32     }
  • 相关阅读:
    [hdu3853]LOOPS(概率dp)
    [poj2096]Collecting Bugs(概率dp)
    lintcode-42-最大子数组 II
    lintcode-39-恢复旋转排序数组
    lintcode-36-翻转链表 II
    lintcode-34-N皇后问题 II
    lintcode-33-N皇后问题
    lintcode-32-最小子串覆盖
    lintcode-31-数组划分
    lintcode-30-插入区间
  • 原文地址:https://www.cnblogs.com/qiaoxin11/p/12579846.html
Copyright © 2011-2022 走看看