源码学习之ArrayList

ArrayList源码分析学习

  1. 首先是ArrayList的定义

    //继承AbstractList抽线类,实现了List、RandomAccess、Cloneable和Serializable接口
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  2. ArrayList源码开头定义的几个成员变量

        //表示ArrayList的默认容量为10,但是在我们初始化为一个空的ArrayList的时候容量并不是10,具体下文解释
        private static final int DEFAULT_CAPACITY = 10;
        //表示空的一个元素数组,在初始化一个空的ArrayList的时候,elementData就等于这个EMPTY_ELEMENTDATA
        private static final Object[] EMPTY_ELEMENTDATA = {};
        //这个就是实际存储数据的数组,从这个可以看出ArrayList是数组实现的
        transient Object[] elementData; 
        //这个就是数组列表的存储数据的size了
        private int size;
  3. 构造函数,ArrayList一共提供了三个构造函数。

    //第一个构造函数,参数initialCapacity为初始化容量,如果initialCapacity为负,则抛出IllegalArgumentException异常,否则就初始化elementData为一个大小为initialCapacity的数组
    public ArrayList(int initialCapacity) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
            this.elementData = new Object[initialCapacity];
        }
    //第二个构造函数,不传入参数,这个时候elementData,就设置成上文定义的空数组,EMPTY_ELEMENTDATA,这个时候数组链表的容量是0,并不是10.
    public ArrayList() {
            super();
            this.elementData = EMPTY_ELEMENTDATA;
        }
    //第三个构造函数,传入参数为另一个集合。这个时候就是用传入集合的元素初始化数组链表。
    public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            size = elementData.length;
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        }
  4. ArryList扩容机制

     //保证容量,这块是外部手动调用扩容的。minCapacity是需要的最小容量。
        public void ensureCapacity(int minCapacity) {
            //最小扩展,如果elementData等于EMPTY_ELEMENTDATA,那么minExpand设置为DEFAULT_CAPACITY,否则minExpand等于0
            int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
            //如果最小需要容量大于最小扩展,那么这个时候需要保证最小需要容量的数值
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }
      //保证容量,这是内部函数调用用来扩容的,在每次添加元素的时候都会调用
        private void ensureCapacityInternal(int minCapacity) {
        //elementData == EMPTY_ELEMENTDATA时,这个时候minCapacity去DEFAULT_CAPACITY和minCapacity大的一个。
        //在初始化一个空的ArrayList时,elementData == EMPTY_ELEMENTDATA,这个时候添加一个元素,检查容量,minCapacity传递的是size+1,也就是1,这个时候minCapacity等于DEFAULT_CAPACITY。
            if (elementData == EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    //上面两个函数调用的函数
     private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
            // overflow-conscious code
            //如果需要保证的最小容量大于elementData的长度,那么这个时候需要扩容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
     //具体的扩容函数
        private void grow(int minCapacity) {
            int oldCapacity = elementData.length;
            //新容量,是原来的容量的1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            //如果新容量不能满足最小容量要求,那么新容量设置成minCapacity
            //从空添加一个元素的时候,minCapacity==DEFAULT_CAPACITY,这个时候容量就扩充到DEFAULT_CAPACITY了。
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            //如果新容量大于MAX_ARRAY_SIZE,那么新容量设置成Integer.MAX_VALUE
            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);
        }
    //如果minCapacity大于MAX_ARRAY_SIZE,那么返回
     private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    总结来说,扩容的机制是在每次添加元素的时候检查容量size+add_size,elementData是空数组的时候,容量会变成DEFAULT_CAPACITY,也就是10。elementData不是空数组的时候,如果size+add_size大于容量,也即是elementData.length,那么就扩容,扩容的方法是首先扩容1.5倍的原容量,然后判断1.5的原容量是否大于size+add_size,如果不大于,那么新容量设置成size+add_size,再检查size+add_size是否大于最大容量Integer.MAX_VALUE - 8,如果大于那么就设置成Integer.MAX_VALUE

  5. ArrayList常用操作

    1. size()

      public int size() {
                  return size;
              }
    2. isEmpty()

      public boolean isEmpty() {
              return size == 0;
          }
    3. contains()

      public boolean contains(Object o) {
              return indexOf(o) >= 0;
          }
      //找到elementData中第一次出现o的下标
      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;
      }
    4. get()

      public E get(int index) {
              //是否越界判断
              rangeCheck(index);
      
              return elementData(index);
          }
      private void rangeCheck(int index) {
      if (index >= size)
          throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
      }
    5. set()

      //修改下标index处的元素
      public E set(int index, E element) {
              rangeCheck(index);
      
              E oldValue = elementData(index);
              elementData[index] = element;
              return oldValue;
          }
    6. add()

      //在后面添加一个元素
       public boolean add(E e) {
               //判断容量
              ensureCapacityInternal(size + 1);  // Increments modCount!!
              elementData[size++] = e;
              return true;
          }
       //在下标index处添加一个元素,有数据的移动
      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++;
      }
    7. remove()

      //删除下标为index的元素,需要后面的元素进行移动
      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;
          }
      //删除赌徒个等于o的元素
      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;
      }
    8. clear

      public void clear() {
              modCount++;
      
              // clear to let GC do its work
              for (int i = 0; i < size; i++)
                  elementData[i] = null;
      
              size = 0;
          }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值