Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JDK1.8 ArrayList 源码解析

JDK1.8 ArrayList 源码解析

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

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

  1. Arraylist的继承&实现关系

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

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

     \* 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
AI代码解释
复制
//无参构造,

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
AI代码解释
复制
    //添加一个元素

    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
AI代码解释
复制
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 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊ArrayList源码(基于JDK1.8)
打个广告,楼主自己造的轮子,感兴趣的请点[github]: https://github.com/haifeiWu/lightconf
haifeiWu
2018/09/11
3590
聊聊ArrayList源码(基于JDK1.8)
Java集合-ArrayList源码解析-JDK1.8
ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。
Java学习录
2019/04/18
2910
ArrayList扩容机制(基于jdk1.8)
一.ArrayList继承了AbstractList,实现了List接口,底层实现基于数组,因此可以认为是一个可变长度的数组。 二.在讲扩容机制之前,我们需要了解一下ArrayList中最主要的几个变量:
全栈程序员站长
2022/07/01
5020
从源码上分析 ArrayList
前言 ArrayList 是 List 接口的一个实现类,那么 ArrayList 的底层是如何实现的呢?让我们来一探究竟。 源码分析 属性 先来看看 ArrayList 中比较重要的两个属性: transient Object[] elementData; private int size; elementData 用来存储 ArrayList 中的元素,其实 ArrayList 的底层是用 Object[] 数组来实现的。 size 指的是的逻辑长度,就好像一个水杯,容量是 600 毫升,但杯中
一份执着✘
2018/06/04
4250
【Java】ArrayList数组的扩容机制 jdk1.8
elementData就是我们的数据要存储的进入的数组,看上边的注释说,如果数组是空的并且满足elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的时候,数组就会被扩容为10;
哈__
2024/04/08
1170
【JDK1.8】JDK1.8集合源码阅读——ArrayList
一、前言 在前面几篇,我们已经学习了常见了Map,下面开始阅读实现Collection接口的常见的实现类。在有了之前源码的铺垫之后,我们后面的阅读之路将会变得简单很多,因为很多Collection的结
joemsu
2018/05/17
8730
从面试角度分析ArrayList源码
ArrayList的底层是由数组实现的,数组的特点是固定大小,而ArrayList实现了动态扩容。
Java旅途
2020/12/18
3250
ArrayList源码分析(基于jdk1.8)(一):源码及基本操作
ArrayList继承了AbstractList类,并实现了List, RandomAccess, Cloneable, java.io.Serializable等接口。其官方描述为 Resizable-array implementation of the List interface。阅读源码doc,如下:
冬天里的懒猫
2020/08/04
3810
ArrayList源码分析(基于jdk1.8)(一):源码及基本操作
Java源码阅读之ArrayList - JDK1.8
当你对某件事情很感兴趣的时候,时间的流逝在感知中都模糊了(是不是很文艺,绕口得都快听不懂了),通俗来说,就是时间过得很快。
格子Lin
2018/09/30
5000
Java源码阅读之ArrayList - JDK1.8
jdk源码分析之ArrayList
* The array buffer into which the elements of the ArrayList are stored.
全栈程序员站长
2022/07/15
1620
ArrayList源码解析
在平时Java,存储数据需要用到列表,而大多时候都能用到ArrayList,比如Mybatis查询数据列表,返回列表都是ArrayList,很多数据的存放也用到了ArrayList。
用户10384376
2023/02/26
2730
ArrayList源码解析
集合系列 List(二):ArrayList
ArrayList 是 List 集合的列表经典实现,其底层采用定长数组实现,可以根据集合大小进行自动扩容。
陈树义
2019/08/27
3940
集合系列 List(二):ArrayList
ArrayList源码解析(基于Java8)扩容删除
首先:执行List<Person> list1 = new ArrayList<>(); 在堆内存开辟了一块空间,既然是new出来的,那我们直接从构造函数入手 很简单一行代码,继续看一下 this.elementData 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 分别是什么 Object[]数组,也就是说该数组可以放任何对象(所有对象都继承自父类Object) static修饰的变量,常驻于方法区,我们不需要new,JVM会提前给我们初始化好,这
JavaEdge
2018/05/16
1.1K0
JDK1.8 ArrayList 扩容详解
arraylist这个数据结构比较简单,总体来说,arraylist 底层结构是数组,他的很多方法都是从数组上面演变而来的,下面分析下arraylist的扩容机制,
全栈程序员站长
2022/08/31
2240
《JavaSE-第十六章》之ArrayList源码与扩容机制
ArrayList底层是一个Object数组,而数组在内存是连续的空间,所以使用ArrayList存储的元素与添加时的顺序是一致的,每一个ArrayList都有一个容量大小,当添加的元素数量大于该数组的容量时,ArrayList会自动扩容。
用户10517932
2023/10/07
2060
《JavaSE-第十六章》之ArrayList源码与扩容机制
ArrayList 源码分析
ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。
Jacob丶
2020/08/05
4220
你注意ArrayList扩容原理了吗
本文主要是从java 1.6-1.8说一下ArrayList的初始容量大小及扩容的思路,主要是底层是ArrayList在扩容的时候会整个复制导致性能底下,所以在大致知道数组容量大小的时候要给定一个合适的初始大小,最大化减小复制的次数。
Spark学习技巧
2018/12/24
1.5K0
ArrayList的初始容量是多少?
最近无意中又看了下ArrayList源码,发现江山已不再啊,很多时候面试自我感觉还不错,总被淘汰呢,也有这方面的原因,自不知了
码农戏码
2021/03/23
1K0
ArrayList实现原理分析(Java源码剖析)ArrayList使用的存储的数据结构ArrayList的初始化ArrayList是如何动态增长ArrayList如何实现元素的移除ArrayList
ArrayList是我们经常使用的一个数据结构,我们通常把其用作一个可变长度的动态数组使用,大部分时候,可以替代数组的作用,我们不用事先设定ArrayList的长度,只需要往里不断添加元素即可,ArrayList会动态增加容量。ArrayList是作为List接口的一个实现。 那么ArrayList背后使用的数据结构是什么呢? ArrayList是如何保证动态增加容量,使得能够正确添加元素的呢?
desperate633
2018/08/27
1.7K0
ArrayList源码+扩容机制分析
ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。
Vincent-yuan
2021/09/08
9040
相关推荐
聊聊ArrayList源码(基于JDK1.8)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档