[JAVA]ArrayList小结

List

框架
在这里插入图片描述

ArrayList

1. Fileds

int DEFAULT_CAPACITY; //初始容量,10
Object[] elementData; //底层数组
int size; //ArryList长度,元素个数

2. Contractors

  1. 无参构造
    elementData指向空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  2. 有参构造:传参初始容量
    直接创建初始容量的数组
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } //省略参数异常代码
    }
  1. 有参构造:传参集合对象
    本质是是用copyOf()方法创建新的数组
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

3. 扩容机制

结论:grow(int minCapacity)方法扩容。扩容时,newCapacity=oldCapacity+OldCapacty>>1

    private Object[] grow(int minCapacity) {//minCapacity是所需的元素个数,其值=add前的数组的元素个数+需要add的元素个数
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            //第一次使用list时
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

ArraysSupport.newLength计算方式如下:

public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // assert oldLength >= 0
        // assert minGrowth > 0
        int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
        if (newLength - MAX_ARRAY_LENGTH <= 0) {
            return newLength;
        }
        return hugeLength(oldLength, minGrowth);
    }

针对newCapacity=oldCapacity+OldCapacty>>1,而不是直接说newCapacity=oldCapacity*1.5,因为在初始化固定容量的list时可能不是直观的1.5倍。计算新容量的公式如下

newCapacity=Math.max(minCapacity - oldCapacity, oldCapacity >> 1) + oldLength

例如,初始化容量为1的list,第二次添加一个元素前,即newCapacity=Math.max(1,0)+1=2
第四次添加一个元素前,即newCapacity=Math.max(1,3)+1=4
综上,容量的变化为1 2 3 4 6…

扩容触发机制:size>elementData.length时。

add添加元素

  • add()的策略:1.判断底层数组容量,够则直接添加元素,否则先扩容;2.添加。但添加操作需要注意的是 System.arraycopy方法的使用。
  • add方法包括以下两类4种情况:增加单个元素(数组末尾追加),增加单个元素(在指定位置增加),增加集合(数组末尾追加),增加集合(在指定位置增加)。
    a. add(E e)方法,方法内调用如下add方法,在数组尾追加。
        private void add(E e, Object[] elementData, int s) {
          //1.判断底层数组容量
          if (s == elementData.length)
              elementData = grow();
          //2.添加。只有这里的数组添加操作时直接完成的,其他会调用System.arraycopy方法
          elementData[s] = e;
          size = s + 1;
      }
      该方法只会返回true
    b. add(int index,E e),在指定位置添加元素,原数组该位置之后的元素全部后移。
        public void add(int index, E element) {
          //判断下标
          rangeCheckForAdd(index);
          final int s;
          Object[] elementData;
          //1.判断底层数组容量
          if ((s = size) == (elementData = this.elementData).length)
              elementData = grow();
          //2.添加
          System.arraycopy(elementData, index,
                           elementData, index + 1,
                           s - index);
          elementData[index] = element;
          size = s + 1;
      }
      该方法无返回。
    
    c. addAll(Collection c)
        public boolean addAll(Collection<? extends E> c) {
          Object[] a = c.toArray();
          int numNew = a.length;
          if (numNew == 0)
              return false;
          Object[] elementData;
          final int s;
          //1.判断底层数组容量
          if (numNew > (elementData = this.elementData).length - (s = size))
              elementData = grow(s + numNew);
          //2.添加
          System.arraycopy(a, 0, elementData, s, numNew);
          size = s + numNew;
          return true;
      }
      c中没有元素时返回false,其余返回true
    d. addAll(int index,Collection c),该方法与c中的方法基本一致
        public boolean addAll(int index, Collection<? extends E> c) {
          rangeCheckForAdd(index);
    
          Object[] a = c.toArray();
          int numNew = a.length;
          if (numNew == 0)
              return false;
          Object[] elementData;
          final int s;
          //1.判断底层数组容量
          if (numNew > (elementData = this.elementData).length - (s = size))
              elementData = grow(s + numNew);
          //2.添加
          int numMoved = s - index;
          if (numMoved > 0)
              System.arraycopy(elementData, index,
                               elementData, index + numNew,
                               numMoved);
          System.arraycopy(a, 0, elementData, index, numNew);
          size = s + numNew;
          return true;
      }
      c中没有元素时返回false,其余返回true

remove删除元素

  • ArrayLsit有两类3种remove方法。分别为remove(int index)、remove(E e)、removeAll(Collection c)。
    a. 两种删除单个元素的remove方法,传参分别是下标、元素,两种元素本质上都调用了fastRemove(Object[] es, int i)方法。
    b. 关于remove(int index)和remove(E e)方法,特别说明以下点:
    ①. 对于存放Integer类型元素的数组,删除方式建议:
      //删除list中下标为2的元素
      list.remove(2);
      //删除list中值为2的元素
      list.remove(Integer.valueOf(2));
    
    ②. 直接删除元素的方法,单次只能删除数组最先出现的元素。
    ③. 传参下标时,返回被删除的元素。传参元素时,返回boolean表示是否删除成功。
    c. removeAll(Collection c)方法。内部调用了batchRemove方法。特别的,与add方法的返回值不同,如a.removeAll(b),表示删除a中的交集元素,但该方法的返回值表示集合a是否发生了变化,而非删除成功与否

retainAll求交集

retainAll(Collection c)方法和removeAll一样,内部调用了batchRemove,返回值也是boolean。a.retainAll(b)表示求集合a和b的交集,并放在a中,返回值也表示集合a是否发生了变化。
方法的返回值表示集合a是否发生了变化,而非删除成功与否**。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值