第二章 ArrayList源码解析

一、对于ArrayList需要掌握的七点内容

  • ArrayList的创建:即构造器
  • 往ArrayList中添加对象:即add(E)方法
  • 获取ArrayList中的单个对象:即get(int index)方法
  • 删除ArrayList中的对象:即remove(E)方法
  • 遍历ArrayList中的对象:即iterator,在实际中更常用的是增强型的for循环去做遍历
  • 判断对象是否存在于ArrayList中:contain(E)
  • ArrayList中对象的排序:主要取决于所采取的排序算法(以后讲)

二、源码分析

2.1、ArrayList的创建(常见的两种方式)

        List<String> strList = new ArrayList<String>();
        List<String> strList2 = new ArrayList<String>(2);

ArrayList源代码:

基本属性:

    //对象数组:ArrayList的底层数据结构
    private transient Object[] elementData;
    //elementData中已存放的元素的个数,注意:不是elementData的容量
    private int size;

构造器:

    /**
     * 创建一个容量为initialCapacity的空的(size==0)对象数组
     */
    public ArrayList(int initialCapacity) {
        super();//即父类protected AbstractList() {}
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /**
     * 默认初始化一个容量为10的对象数组
     */
    public ArrayList() {
        this(10);//即上边的public ArrayList(int initialCapacity){}构造器
    }

在我们执行new ArrayList<String>()时,会调用上边的无参构造器,创造一个容量为10的对象数组。

在我们执行new ArrayList<String>(2)时,会调用上边的public ArrayList(int initialCapacity),创造一个容量为2的对象数组。

注意:

  • 上边有参构造器的super()方法是ArrayList父类AbstractList的构造方法,这个构造方法如下,是一个空构造方法:

        protected AbstractList() {
        }
  • 在实际使用中,如果我们能对所需的ArrayList的大小进行判断,有两个好处:
    • 节省内存空间(eg.我们只需要放置两个元素到数组,new ArrayList<String>(2))
    • 避免数组扩容(下边会讲)引起的效率下降(eg.我们只需要放置大约37个元素到数组,new ArrayList<String>(40))

2.2、往ArrayList中添加对象(常见的两个方法add(E)和addAll(Collection<? extends E> c))

2.2.1、add(E)

strList2.add("hello");

ArrayList源代码:

    /**
     * 向elementData中添加元素
     */
    public boolean add(E e) {
        ensureCapacity(size + 1);//确保对象数组elementData有足够的容量,可以将新加入的元素e加进去
        elementData[size++] = e;//加入新元素e,size加1
        return true;
    }
    /**
     * 确保数组的容量足够存放新加入的元素,若不够,要扩容
     */
    public void ensureCapacity(int minCapacity) {
        modCount++;
        int oldCapacity = elementData.length;//获取数组大小(即数组的容量)
        //当数组满了,又有新元素加入的时候,执行扩容逻辑
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            int newCapacity = (oldCapacity * 3) / 2 + 1;//新容量为旧容量的1.5倍+1
            if (newCapacity < minCapacity)//如果扩容后的新容量还是没有传入的所需的最小容量大或等于(主要发生在addAll(Collection<? extends E> c)中)
                newCapacity = minCapacity;//新容量设为最小容量
            elementData = Arrays.copyOf(elementData, newCapacity);//复制新容量
        }
    }

在上述代码的扩容结束后,调用了Arrays.copyOf(elementData, newCapacity)方法,这个方法中:对于我们这里而言,先创建了一个新的容量为newCapacity的对象数组,然后使用System.arraycopy()方法将旧的对象数组复制到新的对象数组中去了。

2.2.2、addAll(Collection<? extends E> c)

使用方式:

        List<String> strList = new ArrayList<String>();
        strList.add("jigang");
        strList.add("nana");
        strList.add("nana2");

        List<String> strList2 = new ArrayList<String>(2);
        strList2.addAll(strList);

源代码:

    /**
     * 将c全部加入elementData
     */
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();//将c集合转化为对象数组a
        int numNew = a.length;//获取a对象数组的容量
        ensureCapacity(size + numNew);//确保对象数组elementData有足够的容量,可以将新加入的a对象数组加进去
        System.arraycopy(a, 0, elementData, size, numNew);//将对象数组a拷贝到elementData中去
        size += numNew;//重新设置elementData中已加入的元素的个数
        return numNew != 0;//若加入的是空集合则返回false
    }

注意:

  • 从上述代码可以看出,若加入的c是空集合,则返回false
  • ensureCapacity(size + numNew);这个方法在上边讲
  • System.arraycopy()方法定义如下:

    public static native void arraycopy(Object src,  int  srcPos, Object dest, int destPos,  int length);

    将数组src从下标为srcPos开始拷贝,一直拷贝length个元素到dest数组中,在dest数组中从destPos开始加入先的srcPos数组元素。

2.3、获取ArrayList中的单个对象

2.4、删除ArrayList中的对象

2.5、判断对象是否存在于ArrayList中

2.6、遍历ArrayList中的对象

三、总结

  • ArrayList基于数组方式实现,无容量的限制(会扩容)

临时有事儿,剩下的内容之后在写。

时间: 2024-10-13 11:54:30

第二章 ArrayList源码解析的相关文章

Java集合干货系列-(一)ArrayList源码解析

前言 今天来介绍下ArrayList,在集合框架整体框架一章中,我们介绍了List接口,ArrayList继承了AbstractList,实现了List.ArrayList在工作中经常用到,所以要弄懂这个类是极其重要的.构造图如下:蓝色线条:继承绿色线条:接口实现 正文 ArrayList简介 ArrayList定义 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomA

第六章 ReentrantLock源码解析2--释放锁unlock()

最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final ReentrantLock lock = new ReentrantLock(); lock.lock();//获取锁 try { a++;//业务逻辑 } catch (Exception e) { }finally{ lock.unlock();//释放锁 } 注:关于lock()方法的源码解析,请参照"第五章

第十四章 Executors源码解析

前边两章介绍了基础线程池ThreadPoolExecutor的使用方式.工作机理.参数详细介绍以及核心源码解析. 具体的介绍请参照: 第十二章 ThreadPoolExecutor使用与工作机理 第十三章 ThreadPoolExecutor源码解析 1.Executors与ThreadPoolExecutor ThreadPoolExecutor 可以灵活的自定义的创建线程池,可定制性很高 想创建好一个合适的线程池比较难 使用稍微麻烦一些 实际中很少使用 Executors 可以创建4种线程池

ArrayList源码解析

ArrayList源码解析 ArrayList简介: ArrayList 是list接口的一个常用实现类.它的对象可以认为是一维数组的"类版本".我们很快就可以看到,ArrayList 对象可以看做是一维数组的改良版本.类似于数组,ArrayList 对象支持元素的随机访问:也就是说,只要给出元素的索引,任何元素的访问时间都是常数.但是同数组不同的是,ArrayList 对象的大小在程序执行的过程中可以自动进行调整,并且ArrayList对象具有在任何索引位置插入和删除对象的方法,而数

第三章 CopyOnWriteArrayList源码解析

注:在看这篇文章之前,如果对ArrayList底层不清楚的话,建议先去看看ArrayList源码解析. http://www.cnblogs.com/java-zhao/p/5102342.html 1.对于CopyOnWriteArrayList需要掌握以下几点 创建:CopyOnWriteArrayList() 添加元素:即add(E)方法 获取单个对象:即get(int)方法 删除对象:即remove(E)方法 遍历所有对象:即iterator(),在实际中更常用的是增强型的for循环去做

给jdk写注释系列之jdk1.6容器(1):ArrayList源码解析

原文出自吞噬天地,链接整理自ImportNew 给jdk写注释系列之jdk1.6容器(2):LinkedList源码解析 给jdk写注释系列之jdk1.6容器(3):Iterator设计模式 给jdk写注释系列之jdk1.6容器(4)-HashMap源码解析 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析 给jdk写注释系列之jdk1.6容器(6)-HashSet源码解析&Map迭代器 给jdk写注释系列之jdk1.6容器(1):ArrayList源码解析 工作中

面试必备:ArrayList源码解析(JDK8)

面试必备:ArrayList源码解析(JDK8) https://blog.csdn.net/zxt0601/article/details/77281231 概述很久没有写博客了,准确的说17年以来写博客的频率降低到一个不忍直视的水平.这个真不怪我,给大家解释一下. 一是自从做了leader,整天各种事,开会,过需求,无限循环.心很累,时间也被无线压榨 二 我本身也在学习一些其他的技术,比如ReactNative,也看了半天的kotlin,撸了几个groovy脚本.gradle插件. 三 是打

源码解读:ArrayList源码解析(JDK8)

ArrayList源码解析(JDK8) 更详细的讲解可以参考这篇博文,本文只讲解在阅读源码中个人遇到的问题. 面试必备:ArrayList源码解析(JDK8) 构造函数 /** * ArrayList容器默认初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 用于有参构造的空数组 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 用于无参构造的空数组

ArrayList源码解析(一)

目录 1.位置 2.变量和常量 3.构造函数 4.trimToSize()方法 正文 源码解析系列主要对Java的源码进行详细的说明,由于水平有限,难免出现错误或描述不准确的地方,还请大家指出. 回到顶部 1.位置 ArrayList位于java.util包中. 1 package java.util; 2 3 import java.util.function.Consumer; 4 import java.util.function.Predicate; 5 import java.util