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没有实现任何的同步,所以不是线程安全的,其他的添加,删除方法可以自行点开源码查看,相应的很简单。

  • 相关阅读:
    关于matplotlib绘制直方图偏移的问题
    XP下 无法定位程序输入点WSAPoll于动态链接库ws2_32.dll 的解决办法
    Ubuntu 拨号上网及校园网开启IPV6
    php性能优化
    Mac OS X 10.11.6 重置root密码
    php 接口类与抽象类的实际作用
    Redis Cluster集群的搭建与实践
    nginx 反向代理 取得真实IP和域名
    mysql主从配置,出错
    mycat水平分片规则
  • 原文地址:https://www.cnblogs.com/javatalk/p/10123192.html
Copyright © 2011-2022 走看看