Java集合学习1——JDK1.8 ArrayList 详解

索引

1.介绍

2.常用参数

3.构造方法

4.增

5.删

6.改

8.查

9.总结

1.介绍
ArrayList是一个基于数组的集合实现,可以进行对元素的增删改查,可以动态的进行扩容。ArrayList并不是线程安全,所以效率比较高,推荐单线程环境下使用。

2.常用参数

  • elementData :数组
  • size:数组中元素的个数
  • initialCapacity:作为参数传入,为集合的大小

3.构造方法

 public ArrayList(int initialCapacity) {
         //如果参数大于0,则创建一个initialCapacity大小的object数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        }
        //如果参数等于0,则创建一个空数组
        else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        }
        否则抛出异常 
        else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


public ArrayList() {
        //创建一个空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

//构造函数,传入一个容器
public ArrayList(Collection<? extends E> c) {
        //对容器数组化
        elementData = c.toArray();
        //将容器中的元素传入数组
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //创建一个空数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

一共三个构造方法,一个传入数组大小来创建,一个创建一个空数组,最后一个传入一个容器来创建。

4.增
add方法的函数体比较简单,再此之前我们先来看看add方法内部调用的一些方法

- grow:这是一个扩容数组的方法
 private void grow(int minCapacity) {
         //传入数组长度为oldCapacity
        int oldCapacity = elementData.length;
        //定义一个新的长度newCapacity=原来数组的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新的长度小于参数传入的长度,则newCapacity等于传入参数
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //如果新的长度大于数组要求最大长度,则取最大长度
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //最后将数组引用指向复制的新数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
- ensureExplicitCapacity:判断是否有必要扩容
 private void ensureExplicitCapacity(int minCapacity) {
        //检测add操作和remove操作的次数
        modCount++;

        // 传入参数大于数组长度,则扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
  • ensureCapacityInternal:对于一个空数组,这个函数相当在第一次add时就将数组扩容为10。我认为这是一个非常巧妙的操作,在之前1.7版本,是在构造函数时,就创建了一个大小10的数组,这个则是在有add操作时才申请空间。
private void ensureCapacityInternal(int minCapacity) {
        //判断如果这个数组等于空数组,则扩容为一个长度DEFAULT_CAPACITY=10(源码中默认为10)的数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
  • add:添加元素函数
 public boolean add(E e) {
        //检查size+1是否大于数组长度,大于就扩容
        ensureCapacityInternal(size + 1); 
        //添加元素
        elementData[size++] = e;
        return true;
    }

5.删
代码及解释如下

  • rangeCheck:对传入的索引进行边界检查
private void rangeCheck(int index) {
        //太简单,不说了
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
  • remove
public E remove(int index) {
        //越界检测
        rangeCheck(index);
        modCount++;
        //将要删除的元素赋值
        E oldValue = elementData(index);
        //获取移动的位置的大小
        int numMoved = size - index - 1;
        if (numMoved > 0)
            将数组的index+1位置开始向前移动到index位置,移动nummove个元素
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
         //将最后的位置置为null,并size-1
        elementData[--size] = null; // clear to let GC do its work
        //返回删除的元素
        return oldValue;
    }

6.改

  • set
 public E set(int index, E element) {
        //索引合法性检测
        rangeCheck(index);
        //老结果赋值给oldvalue
        E oldValue = elementData(index);
        //赋新值
        elementData[index] = element;
        //返回老的值
        return oldValue;
    }

7.查

  • get
public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }

8.总结
ArrayList具有动态扩容的特点,每次扩容都是一次O(n)级别的操作。它的查询效率很高为O(1),但是其增删会伴随着一次O(n)级别数组赋值,这是它的缺点。

猜你喜欢

转载自blog.csdn.net/weixin_39216383/article/details/80311054