zoukankan      html  css  js  c++  java
  • ArrayList源码阅读

    前言

    数组是我们最常用最简单的数据结构,Java里对数组做了一个简单的包装,就是ArrayList,提供自动扩容的功能。

    最常用法

    list在我们日常代码中最为常用的做法是创建一个list,放入数据,取出数据。如下:

    @Test
    public void testList(){
        final List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("a");
    
        final String one = list.get(0);
        final int size = list.size();
    
        Assert.assertEquals("a", one);
        Assert.assertEquals(4, size);
    }
    

    下面,将从构造函数开始读取源码。

    构造器

    第一步,构造一个list对象

    
    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    注释写的很清楚,构造一个空list,初始化容量为10. 我们来看看这个初始值。

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    

    默认大小的共享的空array实例。可以注意到这是一个static变量,也就是说所有的ArrayList对象共享这个变量。由此可以猜测,这是一个临时值。

    然后看我们的数据存储对象elementData.

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access
    

    ArrayList的容量(capacity)就是这个数组的长度。
    另外,注意修饰关键字transient, 这个不常用,用来表示这个字段不可以被序列化。我们知道,ArrayList实现了Serializable接口,为什么不允许序列化data呢?具体原因参加 http://www.cnblogs.com/woshimrf/p/java-serialize.html

    add

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    

    先保证容量,然后插入数据,size数量+1.

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    
        ensureExplicitCapacity(minCapacity);
    }
    

    针对空list第一次add,判断elementData是不是默认的空对象,若是空对象,计算容量。容量的计算也很有意思。

    private static final int DEFAULT_CAPACITY = 10;
    

    第一次添加后容量就是10了,当超过10之后就肯定要扩容了。

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

    再一次看到modCount这个变量名,和HashMap一样,记载容量发生变化的次数。而扩容的阈值也相当简单,只要保证当前数量+1能够容纳就好。当数组长度不够的时候,扩容。

    
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    

    扩容扩大为1.5倍。然后新建数组,长度为新的容量,复制旧数据。由于过程中没有加锁,ArrayList也不是线程安全的。

    Get

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

    实现相当简单,就是通过数组下标读取元素。但值得学习的是编程结构。比如,这个的范围检测,通过一个有意义的方法名封装了一段代码。清晰易懂。

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

    如何使用线程安全的List

    自己对变化过程加锁,或者使用

    List list = Collection.synchronizedList(new ArrayList());
    

    CopyOnWriteArrayList是一个有趣的例子,它规避了只读操作(如get/contains)并发的瓶颈,但是它为了做到这点,在修改操作中做了很多工作和修改可见性规则。 此外,修改操作还会锁住整个List,因此这也是一个并发瓶颈。所以从理论上来说,CopyOnWriteArrayList并不算是一个通用的并发List。(并发编程网)

    参考

  • 相关阅读:
    49. 字母异位词分组
    73. 矩阵置零
    Razor语法问题(foreach里面嵌套if)
    多线程问题
    Get json formatted string from web by sending HttpWebRequest and then deserialize it to get needed data
    How to execute tons of tasks parallelly with TPL method?
    How to sort the dictionary by the value field
    How to customize the console applicaton
    What is the difference for delete/truncate/drop
    How to call C/C++ sytle function from C# solution?
  • 原文地址:https://www.cnblogs.com/woshimrf/p/arraylist.html
Copyright © 2011-2022 走看看