ArrayList

ArrayList

一、基础

1.父类

Collection->AbstractCollection->AbstractList

2.定义

一个有序的装载对象的动态集合。

2.特点

(1)底层:数组。

(2)默认容量:如果 new ArrayList(),则默认容量为0,在第一次添加数据时,会设置默认容量为10,后续的扩容均进行1.5倍的扩容。

                           最大值为Integer.MAXSIZE-8:214 748 3647-8,(其中这个8存储的是数组对象的元数据)。

(3)优点:有序的;随机访问(通过下标访问)效率高,适合读取数据;

                     可添加null以及重复元素;

                     可自动扩容,每次扩容1.5倍。

(4)缺点:线程不安全,插入和删除速度慢。

(5)写入大量数据时的操作: 如果增加的数据量很大,应该使用list.ensureCapacity()方法,预先设置ArrayList的大小;实例

                            

二、ArrayList的Add()方法解读

Arraylist在进行add操作时:

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  
        elementData[size++] = e;//把新对象放到新的位置上
        return true;
    }

    /**
    *扩容操作
    */
 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    /**    
    *计算容量
    **/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //若当前数组为空数组,则比较10和minCapacity谁大。 
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //若不为空数组,否则返回minCapacity
        return minCapacity;
    }

    /**
     *判断是否需要扩容
    **/
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        //如果超出当前容量,则需要扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**    
    *扩容的增长方法
    **/
 private void grow(int minCapacity) {
        
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //MAX_ARRAY_SIZE指的是Integer.MAX_VALUE - 8;这里要判断是否大于Integer的最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0) 
            newCapacity = hugeCapacity(minCapacity);
        //把旧数组拷贝到新数组中
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    /**    
    * 超出MAX_ARRAY_SIZE时,则返回Integer.MAX_VALUE 
    **/
   private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

(1)定义一个数值 newSize=size+1;【size+1:arrayList的元素个数+1】

         根据newSize这个数值进行如下的计算:  

         若当前数组为空数组,则比较 10 和newSize谁大,谁大则返回谁的数值;

         若不为空数组则直接返回newSize 。

         返回的这个数值记为minCapacity

         ------------------------------------------------------------------------------------------------------------

(2)再确认是否增长:如果 minCapacity 大于 当前的ArrayList的容量  ,则调用增长方法;否则不增长。

         ------------------------------------------------------------------------------------------------------------

(3)调用增长方法,此时定义一个新数组容量:newCapacity=1.5(size+1);

                                   再定义一个旧的数组容量:oldCapacity=当前ArrayList的容量;

增长方法如下:

                       第一步:判断 如果 newCapacity 小于 size+1,则增长到 size+1;(这种情况只发生在arraylist容量为空的情况下)

                       第二步:再判断 如果 newCapacity 大于 int的最大值-8(214 748 3647 - 8),则拿着size+1的这个数值,调用大容量接口得到结果H,把H赋值给newCapacity。

                                  【大容量接口里的具体运算:如果size+1大于 (214 748 3647 - 8 )这个值,则返回int的最大值;否则返回(214 748 3647 - 8 )。】

                      第三步:调用Arrays的copyOf方法,把原来的数组复制到新的数组里,容量为newCapacity。

         ------------------------------------------------------------------------------------------------------------

(4)把新元素添加进新数组中,这里是线程不安全的。

      【 elementData[size++]=e; 这里CPU是分为两步来执行的:1.elementData[size]=e; 2.size++;

 


三、实现线程安全的方式

Vector确实是一个线程安全的List,但它实现安全的方式是对所有操作都加上了Synchronized关键字,这种方式很影响效率,所以并不推荐使用。

若要实现安全,可以采用Collections.synchronizedList(new ArrayList() )创建或创建一个CopyOnWriteArrayList。

实现线程安全的方法对比(【Collections.synchronizedList( new ArrayList() ) 】方法和【创建CopyOnWriteArrayList】的方法):

Collections.synchronizedList( xx )适合写数据,读数据比较差。SynchronizedList里只有listIterator()方法没有加锁,其他的方法都是在代码块上加synchronized。

[-插播一下 - Collections.synchronizedList()的源码解析:如果这个list支持随机访问,那么我们就创建一个SynchronizedRandomAccessList,否则我们创建SynchronizedList。]

 public static <T> List<T> synchronizedList(List<T> list) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
    }

CopyOnWriteArrayList适合读数据,写数据操作性能差。所有涉及到对数据有变动的操作,都在方法里加ReetrantLock。

[- 插播一下 - CopyOnWriteArrayList的 add() 方法源码解析:加上ReetrantLock后将其变成数组,然后分为两步:

                   (1)把旧数组中的数据通过Arrays.copyOf()方法放到新数组中(新数组的容量为旧数组容量+1);

                   (2)把新数据放入新数组中。]

  public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

 


四、ArrayList源码中的两个空数组

DEFAULTCAPACITY_EMPTY_ELEMENTDATAEMPTY_ELEMENTDATA的区别:

从构造函数上来讲,无参构造时,用DEFAULTCAPACITY_EMPTY_ELEMENTDATA作为引用;有参构造时(如果给定的容量为0或者是个空集合),用EMPTY_ELEMENTDATA作为引用。
若容量为0,则指向EMPTY_ELEMENTDATA

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值