ArrryList中比较重要的源码分析

属性

        /**
         * serialVersionUID-序列化的版本号
         * DEFAULT_CAPACITY-默认容量
         * EMPTY_ELEMENTDATA-是一个Object类型的数组
         * DEFAULTCAPACITY_EMPTY_ELEMENTDATA-同上面的一样
         * elementData-是一个缓存数组
         * size数组中元素的数量
         */

三个构造方法

分别为:指定大小初始化、无参初始化(默认)、指定初始数据初始化。

  //指定大小初始化构造放啊
  public ArrayList(int initialCapacity) {//initialCapacity=指定容量大小
        if (initialCapacity > 0) {
             //elementData 是保存数组的容器,默认为 null
            //new一个object数组,赋给elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {//等同于无参初始化构造方法
            //一个空数组,赋给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {//小于0抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    //无参初始化(默认)构造方法
    public ArrayList() {
        //一个空数组,赋给elementData
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    //指定初始数据初始化构造方法
    public ArrayList(Collection<? extends E> c) {
        //toArray()是构造一个object数组,然后进行数据拷贝,如果此时转型则会抛出ClassCastException异常
        Object[] a = c.toArray();
        //如果给定的集合(c)数据有值
        if ((size = a.length) != 0) {//size=0
            //判断c集合元素类型是否等于ArrayList,等与就直接赋值,集合元素类型不是 Object 类型,我们会转成 Object
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            //等同于无参初始化构造方法
            elementData = EMPTY_ELEMENTDATA;
        }
    }

Add(object o)方法

主要分两部
1、判断需不需要扩容,需要则执行扩容操作
2、直接赋值
总结
1、扩容后=扩容前1.5倍
2、数组溢出意思:数组容量最小不能小于0,最大不能大于Integer 的最大值
3、并发时ArrayList时不安全的:因为他只是简单的赋值,并没有添加安全操作
4、扩容是判断添加该元素后,数组容量是否>之前数组默认容量,不大于,不进行扩容,大于,进行扩容,并且在扩容后还要判断:新数组容量是否>旧数组容量,大于则不扩容,不大于则扩容
注意
1、mount解释为数组修改次数

ArrayList<Object> arrayList = new ArrayList<>(10);//注意这里给集合初始化容量=10
        for (int i=0;i<=10;i++){
            arrayList.add(i);
        }
        
public boolean add(E e) {
        //确保数组大小是否足够,不够执行扩容,size 为当前数组的大小
        ensureCapacityInternal(size + 1);  //size=0
        //直接赋值,线程不安全的
        elementData[size++] = e;
        //直接返回true,说明执行add方法一定会成功
        return true;
    }

private void ensureCapacityInternal(int minCapacity) { //minCapacity=1
        //elementData是object数组引用,minCapacity=1
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //判断缓存数组大小是否相等默认空数组容量:第一次添加元素肯定相等,成功添加元素后就不会相等了
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY默认=10
        }
        return minCapacity;
    }
private void ensureExplicitCapacity(int minCapacity) {
        //记录数组被修改,此阶段没啥用
        modCount++;
        //判断需不需要扩容:add执行后大于现有的数组的长度,则执行扩容,反之则直接赋值
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
//最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //二进制位运算(oldCapacity >> 1)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // 如果扩容后的值 > jvm 所能分配的数组的最大值,,那么就用 Integer 的最大值,并且JVM就不会给数组分配内存了
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //这里应该是关于拷贝的事
        elementData = Arrays.copyOf(elementData, newCapacity);//扩容:将原来的数组中的数据克隆到新数组中,并且缓存数组容量也扩大1.5倍
    }

迭代器—Iterator

ArrayList<Object> arrayList = new ArrayList<>(10);//注意这里给集合初始化容量=10
        for (int i=0;i<=10;i++){
            arrayList.add(i);
        }
        //判断arrayList是否还存在元素A
        arrayList.iterator().hashNext()
        //取出元素A
        arrayList.iterator().next()
        //移除元素A
        arrayList.iterator()remove()

//实例
Iterator<Integer> iterator = arrayList.iterator();
        for (int i = 0; i < arrayList.size(); i++) {
            if (iterator.hasNext()){
                System.out.print(iterator.next());
            }
        }
        
public Iterator<E> iterator() {
        return new Itr();
    }

private class Itr implements Iterator<E> {
        int cursor; // 迭代过程中,下一个元素的位置,默认从 0 开始
        int lastRet = -1; 
        int expectedModCount = modCount;// expectedModCount 表示迭代过程中,期望的版本号

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification()//判断 期待版本号与 modCount 是否相同
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
           //具体实现省略
        }
        //判断 期待版本号与 modCount 是否相同
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

remove(object o)删除

删除元素有很多种方式,比如根据数组索引,根据值删除,根据集合删除等等,其实思路都差不多,下面选取根据值删除
思路:判断是否等于null,不等于null后判断数组中是否有该值,有着删除,并且将删除后的数组向前移位。数组中无删除的值则直接返回。

ArrayList<Object> arrayList = new ArrayList<>(10);
arrayList.add("asd");
arrayList.remove("asd");

public boolean remove(Object o) {//0=""asd
       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;
   }
   
private void fastRemove(int index) {//index=0
        modCount++;
        // numMoved 表示删除 index 位置的元素后,需要从 index 后移动多少个元素到前面去
        int numMoved = size - index - 1;//size=数组元素数量
        if (numMoved > 0)
        // index+1表示从 index +1 位置开始被拷贝,拷贝的起始位置是 index,长度是 numMoved
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
            //数组最后一个位置赋值 null
        elementData[--size] = null; // 清除以让GC完成它的工作
    }

get(int index)方法

简单

public E get(int index) {
        //判断index是否在这个范围[0,size)
        rangeCheck(index);
        return elementData(index);
    }

private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

set(int index, E element)方法

在指定位置修改元素,注意不是 “ 添加 ” 是 “ 修改 ”

public E set(int index, E element) {
        //判断index是否在这个范围[0,size)
        rangeCheck(index);
        E oldValue = elementData(index);
        //修改index索引处的值=element
        elementData[index] = element;
        return oldValue;
    }

private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值