深入理解ArrayLIst

1,概念

ArrayList是一个其容量能够动态增长的动态数组,但和数组会有点不一样。下面细说

特性:将会在下面的源码片段中发现,没有一个代码片段使用synchronized关键字
因此,ArrayList是线程不安全的,建议在单线程中使用

2,类关系图

在这里插入图片描述

3,走进源码

数据结构

//默认容量
private static final int DEFAULT_CAPACITY = 10;
//默认存储区
transient Object[] elementData
//数组长度
private int size;

还有两个字段

官方解释:用于空实例的共享空数组实例
这个用于在new对象指定大小为0的时候,初始化ArrayList,下面的构造函数可以看到
private static final Object[] EMPTY_ELEMENTDATA = {};
官方解释:共享的空数组实例用于默认大小的空实例。我们将其与EMPTY_ELEMENTDATA区别开来,以了解添加第一个元素时需要充气多少
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

3.1 构造函数

构造一个指定大小的ArrayList

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        	//如果指定大小为0的时候,
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

空构造函数,构造一个默认大小的实例

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

根据一个集合,来构造一个新的ArrayList,并带有集合元素数据

 public ArrayList(Collection<? extends E> c) {
 		//将集合转换为数组类型
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
        //如果elementData不是Object[]类型的话,就转换一下
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
        	//c集合的长度为0的时候
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

3.2添加元素

  public boolean add(E e) {
  		//size+1:预计新添元素后的数组大小
  		//保证有足够的容量存储数据元素
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal()方法,

private void ensureCapacityInternal(int minCapacity) {
		//这个是是否需要扩容       这个是计算实际容量
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

ensureExplicitCapacity(int )方法,根据calculateCapacity()方法的返回值判断是否够容量,按需要会都自动扩容

  private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        //minCapacity是预计新添元素后的容量
        //预计新添元素后大小与原始数组大小相比
        if (minCapacity - elementData.length > 0)
        //大于0,表示默认容量不够用了,需要扩容
            grow(minCapacity);
    }

grow()方法。扩容机制
当elementData.length=0的时候,直接令newCapacity = minCapacity
当elementData.length!=0,原始长度+原始长度/2 标准来扩容
(当然,不允许长度超过最大正整数)

  private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //原始长度+原始长度/2
        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);
    }

hugeCapacity()方法。判断当前容量是否超过最大正整数

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

calculateCapacity()方法,计算容量,用于构造(扩容)一个数组存储对象
当新添元素后:
当elementData ={}时候,返回10,用于构造一个长度为10的object【】对象
当elementData !={}时候,
1,默认容量10还够用,则返回10
2,超出了默认容量10 ,则返回size+1(10+1),也就是动态扩容

  private static int calculateCapacity(Object[] elementData, int minCapacity) {
  		//如果elementData={},那么返回一个最大值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //用(size+1)与默认大小相比,谁大返回谁,
        //该返回值用于判断将要新添的元素是否还有容量
        //minCapacity等同于size+1
        return Math.max(DEFAULT_CAPACITY(值为10, minCapacity);
        }
        return minCapacity;
    }

3.3删除元素

方法1,根据指定下标删除元素

public E remove(int index) {
		//判断下标是否超出长度
        rangeCheck(index);
        modCount++;
        //返回指定下标的值
        E oldValue = elementData(index);
        //将要移动元素的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
        //将index后面的元素整体向前移动一步
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //将末端的元素置空
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

elementData()方法,返回指定下标的元素

   E elementData(int index) {
        return (E) elementData[index];
    }

方法2,根据指定元素的值删除

 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;
    }

fastRemove()方法
官方解释:专用的remove方法,跳过边界检查,并且不返回删除的值

  private void fastRemove(int index) {
        modCount++;
        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
    }

方法三,删除所有元素

   public void clear() {
        modCount++;

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

        size = 0;
    }

方法四,删除从fromIndex 到toIndex 区域的元素

 protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

3.4 更改元素

  • set(int index, E element):将指定下标的元素设为element
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
  • sort(Comparator<? super E> c):按照指定的排序规则排序
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
  • subList( int from , int to ):返回从from到to之间的列表
   public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
  • toArray():将列表转化为数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
  • trimToSize( ):修改当前实例的容量是列表的当前大小
public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

3.5 查找

  • contains(Object o):如果包含元素o,则返回为true
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
  • indexOf( Object o ):返回此列表中指定元素的第一次出现的索引,如果列表不包含,返回-1
    indexof()
  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;
    }
  • get(int index):返回指定索引的元素
   public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值