zoukankan      html  css  js  c++  java
  • 【Java集合】-- ArrayList源码解析


    ArrayList是一种以数组实现的List,与数组相比,它具有动态扩展的能力,因此也可称之为动态数组。

    继承体系

    图片

    • ArrayList实现了List, RandomAccess, Cloneable, java.io.Serializable等接口。
    • ArrayList实现了List,提供了基础的添加、删除、遍历等操作。
    • ArrayList实现了RandomAccess,提供了随机访问的能力。
    • ArrayList实现了Cloneable,可以被克隆。
    • ArrayList实现了Serializable,可以被序列化

    源码解析

    1.属性

    //默认初始容量
    private static final int DEFAULT_CAPACITY = 10;
    //空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //空数组,new ArrayList()时使用,添加第一个元素的时候会重新初始为默认容量大小
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //保存要存储元素的数组
    transient Object[] elementData;
    //数组长度
    private int size;
    

    2.构造方法

    无参构造

    public ArrayList() {
        //调用默认空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    int型参数的构造方法

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果传入的值大于0,则直接按照传入的大小来构造数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //等于0,则赋值空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    

    Collection型参数构造方法

    public ArrayList(Collection<? extends E> c) {
        //把传入集合中的数组赋值给elementData
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
          // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //判断elementData的类型是否为Object[],如果不是重新把elementData拷贝为Object[]类型
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //传入的是一个空集合,则把elementData赋值为默认空数组
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    

    3.添加元素

    add(E e)方法

    源码:

    public boolean add(E e) {
        //检查是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //把新元素添加到数组末尾
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        //如果ArrayList中elementData 为null则需要创建数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //取传入长度与默认数组长度较大的一个作为创建数组的长度
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    
        ensureExplicitCapacity(minCapacity);
    }
    private void ensureExplicitCapacity(int minCapacity) {
        //数组被修改所以+1
        modCount++;
        // overflow-conscious code
        //要存储的长度大于数组长度则需要扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //新容量为旧容量的1.5倍
        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);
    }
    

    添加元素很简单就是直接判断是否扩容,然后把元素添加到队尾。

    add(int index, E element)

    public void add(int index, E element) {
        //判断传入索引是否合法
        rangeCheckForAdd(index);
        //检测是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将index位置的元素后移一位
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    

    3.获取元素

    ArrayList中获取元素只有一个方法就是get,源码:

    public E get(int index) {
        //检测索引是否超出范围
        rangeCheck(index);
    
        //返回对应索引位置的元素
        return elementData(index);
    }
    

    4.删除元素

    remove(int index)通过索引删除

    public E remove(int index) {
        rangeCheck(index);
    
        modCount++;
        //获取对应索引位置的元素
        E oldValue = elementData(index);
    
        //计算要移动元素的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //把index索引之后的元素全部前移一位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //把数组最后一个存在元素的位置赋值为空
        elementData[--size] = null; // clear to let GC do its work
    
        return oldValue;
    }
    

    remove(Object o)删除指定元素

    public boolean remove(Object o) {
        if (o == null) {
            //传入为null
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    //完成数组元素的删除
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    private void fastRemove(int index) {
        modCount++;
        //要移动元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    
  • 相关阅读:
    关于秒杀的系统架构优化思路
    如何设计一个秒杀系统
    RabittMQ实践(二): RabbitMQ 与spring、springmvc框架集成
    RabittMQ实践(一): RabbitMQ的安装、启动
    Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
    Linux 网络 I/O 模型简介(图文)
    Java 网络编程(六) 使用无连接的数据报(UDP)进行通信
    Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信
    Java 网络编程(四) InetAddress类
    Java 网络编程(三) 创建和使用URL访问网络上的资源
  • 原文地址:https://www.cnblogs.com/wf614/p/12383311.html
Copyright © 2011-2022 走看看