前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK1.8 ArrayList 源码解析

JDK1.8 ArrayList 源码解析

原创
作者头像
tanoak
修改2018-07-26 23:13:12
3840
修改2018-07-26 23:13:12
举报
文章被收录于专栏:java闲聊

源码的解读逻辑按照程序运行的轨迹展开

  1. Arraylist的继承&实现关系

打开ArrayList源码,会看到有如下的属性定义,

  1. ArrayList中定义的属性
代码语言:txt
复制
    /\*\*

     \* Default initial capacity. 

     \* 初始容量

     \*/

    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 = {};



    /\*\*

     \* 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; 



     /\*\*

     \* The size of the ArrayList (the number of elements it contains).

     \* 实际数据的数量

     \* @serial

     \*/

    private int size;



    /\*\*

     \* The maximum size of array to allocate.

     \* Some VMs reserve some header words in an array.

     \* Attempts to allocate larger arrays may result in

     \* OutOfMemoryError: Requested array size exceeds VM limit

     \* Integer 最大值

     \*/

    private static final int MAX\_ARRAY\_SIZE = Integer.MAX\_VALUE - 8;

当运行 ArrayList<Integer> list = new ArrayList<>() ; ,因为它没有指定初始容量,所以它调用的是它的无参构造

代码语言:txt
复制
//无参构造,

public ArrayList() {

    this.elementData = 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);

    }

}

当我们仅仅new出一个ArrayList时,它仅仅只会创建一个空数组,由此我们可以得知它的初始化操作被延迟到了第一次add()

代码语言:txt
复制
    //添加一个元素

    public boolean add(E e) {

        ensureCapacityInternal(size + 1);  // Increments modCount!!

        elementData[size++] = e;

        return true;

    }

    

    private void ensureCapacityInternal(int minCapacity) {

        if (elementData == DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA) {

            minCapacity = Math.max(DEFAULT\_CAPACITY, minCapacity);

        }



        ensureExplicitCapacity(minCapacity);

    }

    public static int max(int a, int b) {

        return (a >= b) ? a : b;

    }

//判断是否要扩容,minCapacity的值大于add数据之前的大小,就调用grow方法,进行扩容,否则什么也不做

    private void ensureExplicitCapacity(int minCapacity) {

        modCount++;

        // overflow-conscious code

        if (minCapacity - elementData.length > 0)

            grow(minCapacity);

    }

    private void grow(int minCapacity) {

        // overflow-conscious code

        int oldCapacity = elementData.length;

        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩充capacity,将其向右一位再加上原来的数,实际上是扩充了1.5倍

        if (newCapacity - minCapacity < 0)

            newCapacity = minCapacity;

        if (newCapacity - MAX\_ARRAY\_SIZE > 0)//确保数组的容量不大于Integer的最大值

            newCapacity = hugeCapacity(minCapacity);

        // minCapacity is usually close to size, so this is a win:

        elementData = Arrays.copyOf(elementData, newCapacity);//复制

    }

对源码阅读有问题的可以把以下代码复制自行运行,这是一个简版的ArrayList,是我从JDK源码中抽取出来的,理解下面的代码再去看JDK的源码相信就很简单了

代码语言:txt
复制
package com.tanoak.list.arraylist;



import java.io.Serializable;

import java.util.Arrays;

import java.util.Collection;



/\*\*

 \* @Desc  自定义ArrayList集合类, 基于数组实现

 \*/

public class TkArrayList<E> implements Serializable {





    /\*\*

     \*

     \* 初始容量

     \*/

    private static final int DEFAULT\_CAPACITY = 10;



    /\*\*

     \* 空数组

     \*/

    private static final Object[] EMPTY\_ELEMENTDATA = {};



    /\*\*

     \* 默认容量的空数组

     \*/

    private static final Object[] DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA = {};



    /\*\*

     \* 真正存放数据的数组

     \*/

     transient Object[] elementData;



    /\*\*

     \* 实际数据的数量

     \*/

    private int size;



    /\*\*

     \* 记录了ArrayList结构性变化的次数

     \*/

    protected transient int modCount = 0;





    /\*\*

     \* Integer 最大值

     \*/

    private static final int MAX\_ARRAY\_SIZE = Integer.MAX\_VALUE - 8;





    public TkArrayList() {

        this.elementData = DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA;

    }





    /\*\*

     \* 指定数组大小

     \* @param initialCapacity

     \*/

    public TkArrayList(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);

        }

    }



    /\*\*

     \* 构造一个包含指定元素的list,这些元素的是按照Collection的迭代器返回的顺序排列的

     \* @param c

     \*/

    public TkArrayList(Collection<? extends E> c) {

        elementData = c.toArray();

        if ((size = elementData.length) != 0) {

            // c.toArray might (incorrectly) not return Object[] (see 6260652)

            if (elementData.getClass() != Object[].class){

                elementData = Arrays.copyOf(elementData, size, Object[].class);

            }

        } else {

            // replace with empty array.

            this.elementData = EMPTY\_ELEMENTDATA;

        }

    }

    //增

    /\*\*

     \*  新增元素

     \* @param e

     \* @return

     \*/

    public boolean add(E e) {

        // Increments modCount!!

        ensureCapacityInternal(size + 1);

        elementData[size++] = e;

        return true;

    }



    /\*\*

     \*

     \* @param minCapacity

     \*/

    private void ensureCapacityInternal(int minCapacity) {

        if (elementData == DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA) {

            minCapacity = Math.max(DEFAULT\_CAPACITY, minCapacity);

        }



        ensureExplicitCapacity(minCapacity);

    }



    /\*\*

     \* 判断是否扩容

     \* @param minCapacity

     \*/

    private void ensureExplicitCapacity(int minCapacity) {

        modCount++;



        // overflow-conscious code

        if (minCapacity - elementData.length > 0){

            grow(minCapacity);

        }



    }

   //进行扩容

    private void grow(int minCapacity) {

        // overflow-conscious code

        int oldCapacity = elementData.length;



        //扩充capacity,将其向右一位再加上原来的数,实际上是扩充了1.5倍

        int newCapacity = oldCapacity + (oldCapacity >> 1);

        if (newCapacity - minCapacity < 0){

            newCapacity = minCapacity;

        }

        //确保数组的容量不大于Integer类型最大值

        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;

    }

    //查

    /\*\*

     \* 根据索引 调用 elementData 返回值

     \* @param index

     \* @return

     \*/

    public E get(int index) {

        rangeCheck(index);



        return elementData(index);

    }



    /\*\*

     \* 根据索引取出值

     \* @param index

     \* @return

     \*/

    E elementData(int index) {

        return (E) elementData[index];

    }



    private void rangeCheck(int index) {

        if (index >= size){

            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        }

    }



    /\*\*

     \* 越界信息

     \* @param index

     \* @return

     \*/

    private String outOfBoundsMsg(int index) {

        return "Index: "+index+", Size: "+size;

    }



    //删

    /\*\*

     \*

     \* @param index

     \* @return

     \*/

    public E remove(int index) {

        rangeCheck(index);

        modCount++;

        E oldValue = elementData(index);



        int numMoved = size - index - 1;

        if (numMoved > 0){

            System.arraycopy(elementData, index+1, elementData, index, numMoved);

        }

        // clear to let GC do its work

        elementData[--size] = null;



        return oldValue;

    }

    

    //改

    public E set(int index, E element) {

        rangeCheck(index);



        E oldValue = elementData(index);

        elementData[index] = element;

        return oldValue;

    }

}

ArrayList比较难理解的就是扩容,思路首先理清楚,但是只要理清楚几个属性在方法中所做的判断,然后运行上面简版的源码,多熟悉几次就不成问题了

* 如理解有误,请指正

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档