zoukankan      html  css  js  c++  java
  • java集合核心源码01——ArrayList

    首先呢,对于ArrayList,相当于一个动态数组,里面可以存储重复数据,并且支持随机访问,不是线程安全的。对于更多的底层东西,且听分解。

    打开源码,先看继承了哪些类,实现了哪些接口,然后继承的这些类或接口是否还有父类,一直深挖到顶部

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    可以看出,ArrayList集合继承了AbstractList类,实现了List,RandomAccess,Cloneable,Serializable这一系列接口,一个一个分析。

    其中呢AbstractList类最终也是实现了Collection接口,List也是继承了Collection接口,同时呢Collection接口继承了Iterable接口。

    对于Iterable接口呢,源码中解释说,for-each循环可以与任何实现了Iterable接口的对象一起工作,就是说该集合可以使用for-each循环。

    对于Cloneable,Serializable这两个接口,代表该类支持克隆和序列化。

    对于RandomAccess,实现了该接口,那么该类就支持快速的随机访问。LinkedList就没有实现该接口,需要用迭代器进行遍历。

    对于AbstractList类,里面有一个属性modCount,这个属性主要是由集合的迭代器使用的,在迭代的过程中,会检查当前的List的modCount和自己保存的比较,是否发生了变化(变化是指该集合是否被其他线程并发修改),如果发生变化,就抛出java.util.ConcurrentModificationException异常,这种行为就是fail-fast机制

    接下来,我们真正的走进ArrayList源码:

     transient Object[] elementData;

    首先,ArrayList底层也是封装的一个数组,这个数组是被transient关键字修饰的,代表对象的临时数据,持久化对象时,不需要维持,所以不需要参与序列化,即用该关键字修饰。(该关键字修饰的实例变量不参与序列化)

    然后呢,看一下ArrayList有哪些构造器:

      private static final int DEFAULT_CAPACITY = 10;//默认容量大小为10
      private int size;//提供私有变量保存数组的长度
      /**
      *接收一个int型的整数,初始化数组容量
      */
      public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }
    
        /**
         * 不接收任何参数,采用默认容量10
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
        /**
         * 接收一个Collection类型的集合,把集合的元素复制到数组中
         * 
         */
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            if ((size = elementData.length) != 0) {
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

    另外呢讲一下ArrayList的扩容:

    ensureCapacity()方法是用来首先计算出一个最小扩展的容量minExpand,然后所需要的最小容量和最小扩展容量相比较,如果大于,就会进入ensureExplicitCapacity方法,也是进行判断后,然后进入主要的方法grow方法,计算新的容量大小为旧容量+旧容量/2(右移一位相当于除以2)即为原来长度的1.5倍,为什么是1.5倍呢?因为由实验可得出,1.5倍不会浪费太大的内存。

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    public
    void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }

    除此之外呢,还有一个方法,这个方法是来判断数组中元素个数和数组长度的,来进行适时的释放内存空间,适时的调用此方法减少内存占用:

     public void trimToSize() {
            modCount++;
            if (size < elementData.length) {
                elementData = (size == 0)
                  ? EMPTY_ELEMENTDATA
                  : Arrays.copyOf(elementData, size);
            }
        }

    从源码中可以看出,ArrayList没有实现任何的同步,所以不是线程安全的,其他的添加,删除方法可以自行点开源码查看,相应的很简单。

  • 相关阅读:
    Advanced Configuration Tricks
    Reviewing the Blog Module
    Editing and Deleting Data
    Making Use of Forms and Fieldsets
    Understanding the Router
    SQL Abstraction and Object Hydration
    Preparing for Different Databases
    Java学习理解路线图
    Openstack学习历程_1_视频
    CentOS安装Nginx负载
  • 原文地址:https://www.cnblogs.com/javatalk/p/10123192.html
Copyright © 2011-2022 走看看