zoukankan      html  css  js  c++  java
  • ArrayList详解

    本文将结合java源码详细介绍ArrayList的底层实现:

    ​ 首先ArrayList的底层是一个Object类型的数组,当执行new ArrayList()的时候,数组的长度是0,当对象调用add()函数的时候,会创建一个初始长度为10的数组。在ArrayList里面有两个构造函数,无参的构造函数会创建一个默认长度为10的数组,当使用有参的构造函数时,若传入的参数大于0,则创建一个对应参数大小的数组,若等于0则创建一个默认长度10的数组,否则报出一个IlleglArgumentException的异常。

    private static final int DEFAULT_CAPACITY = 10;
    
        /**
         * Shared empty array instance used for empty instances.
         */
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
        /**
         * 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 = {};
    
    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);
            }
    }
    
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    当调用add函数的时候,源代码如下。不要索引的add函数会直接将元素加在当前arrayList对象的末尾,会首先使用ensureCapacityInternal函数,会判断此时的ArrayList对象是否需要进行扩容,会比较当前的容量和minCapacity的值,minCapacity代表的是当前对象加入了当前元素个数,当加入之前的数组为空时,则minCapacity记为起始默认的数组长度10,否则记为加入之前对象中元素的个数加一。

    若此时的minCapacity大于当前数组的长度是,则使用grow()函数对数组进行扩容,然后对扩容后的数组给size++索引位置赋值给添加元素,否者直接对size++出的直接赋值即可。

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        elementData[index] = element;
        size++;
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

    此时的grow函数才是真正地对ArrayList对象进行扩容,若当前的minCapacity大于当前数组长度的1.5则需要新的数组需要扩容到之前的1.5倍,否则需要新数组长度等于minCapacity长度大小。(什么情况下会发生呢?)同时在grow函数里面还需要和ArrayList可以的最大size(MAX_ARRAY_SiZE)比较,如果此时的minCapacity小于零会报OOM错误,否则会将更新的长度赋值为Integer.MAX_VLUE长度。然后使用Arrays里面的copyOf进行复制数组。

    private void grow(int minCapacity) {
        // overflow-conscious code 这是为了防止int溢出所作的处理
        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);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
    }
    

    Arrays里面的copyOf函数会重新创建一个数组长度为参数的数组,将原来数组里面的元素按照原来的位置一次存入新的数组。

    知之为知之,不知为不知
  • 相关阅读:
    Postgresql HStore 插件试用小结
    postgres-xl 安装与部署 【异常处理】ERROR: could not open file (null)/STDIN_***_0 for write, No such file or directory
    GPDB 5.x PSQL Quick Reference
    postgresql 数据库schema 复制
    hive 打印日志
    gp与 pg 查询进程
    jquery table 发送两次请求 解惑
    python 字符串拼接效率打脸帖
    postgresql 日期类型处理实践
    IBM Rational Rose软件下载以及全破解方法
  • 原文地址:https://www.cnblogs.com/bevishe/p/13883274.html
Copyright © 2011-2022 走看看