JDK源码阅读—ArrayList的实现
1 继承结构图
ArrayList继承AbstractList,实现了List接口

2 构造函数
transient Object[] elementData; // 数组保存元素 private int size; // 记录长度
size记录ArrayList的长度,elementData记录元素的值
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。transient详细介绍如链接:transient关键字介绍
三种构造方法
public ArrayList(int initialCapacity)
参数为长度,必须为大于等于0整数,如果传入0,与第二种构造方法结果相同,都是建立一个空的Object数组
public ArrayList()
创建一个空的Object数组
public ArrayList(Collection <?extendsE> c)
如果参数不为空,则使用Collection的toArray方法,把c转为对象数组,否则创建一个空的Object数组
3 需要注意的方法
    public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
常使用的是set(E element)这个方法 set方法如果使用set(int index, E element)这个方法,index对应的位置如果已经有值,该值会被新set的对象替换,并且返回旧值
    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++;
    }
平时使用都是使用add(E element),如果使用了add(int index, E element)这个方法,从上图的实现来看,它会先把记录元素的数组长度加1,然后把index之后的元素全部都后移一位,然后把新插入的元素放在索引为index的位置
    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);
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }
remove(int index)的删除方法是把index之后的元素都往前移动一个位置,所以如果你用for循环遍历ArrayList并且在循环中满足某个条件就remove掉一个元素,那么就会抛出IndexOutOfBoundsException
    public boolean remove(Object o) {
        if (o == 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;
    }
Remove(Object o)会从前往后查找,找到第一个相等的对象进行删除,删除的原理也是后面的元素前移一位,所以遍历ArrayList最好用迭代器进行遍历。
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
addAll(int index, Collection c)如果当前ArrayList的长度小于index,直接从index开始,把c的元素按顺序摆放,如果当前ArrayList的长度大于Index,则把c插入到当前ArrayList的index 到index+c.length的位置,再把原ArrayList的剩余元素接到后面
4 不常用方法
    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
batchRemove不常用方法,可以批量删除当前list中包含(complement == true)或不包含(complement == false)某个集合c中所有元素。并返回操作的结果。
备注
上面说到了,直接使用ArrayList的remove在遍历中很容易出错,下面看看它的迭代器是怎么实现remove的
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        Itr() {}
        public boolean hasNext() {
            return cursor != size;
        }
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
cursor记录要访问的下一个index,lastRet记录当前已经读到的index,迭代器在remove的时候,先调用ArrayList的remove方法删除对应元素,同时,会把cursor和lastRet都减1,自动帮我们完成了元素的重新定位。
本文来自我的个人博客:http://blog.duchangchun.com/2018/12/29/jdk_arraylist/
JDK源码阅读—ArrayList的实现的更多相关文章
- JDK源码阅读——ArrayList
		序 如同C语言中字符数组向String过渡一样,作为面向对象语言,自然而然的出现了由Object[]数据形成的集合.本文从JDK源码出发简单探讨一下ArrayList的几个重要方法. Fields / ... 
- JDK源码阅读--ArrayList
		public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ... 
- JDK源码阅读(三):ArraryList源码解析
		今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ... 
- JDK源码阅读-FileDescriptor
		本文转载自JDK源码阅读-FileDescriptor 导语 操作系统使用文件描述符来指代一个打开的文件,对文件的读写操作,都需要文件描述符作为参数.Java虽然在设计上使用了抽象程度更高的流来作为文 ... 
- JDK源码阅读(一):Object源码分析
		最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ... 
- 利用IDEA搭建JDK源码阅读环境
		利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ... 
- JDK源码阅读-FileOutputStream
		本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ... 
- JDK源码阅读-FileInputStream
		本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ... 
- JDK源码阅读-ByteBuffer
		本文转载自JDK源码阅读-ByteBuffer 导语 Buffer是Java NIO中对于缓冲区的封装.在Java BIO中,所有的读写API,都是直接使用byte数组作为缓冲区的,简单直接.但是在J ... 
随机推荐
- 《转》couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145
			couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145,有须要的朋友能够參考下. 应为昨天安装的时候没及时 ... 
- HTML代码简写法:Emmet和Haml(转)
			HTML代码写起来很费事,因为它的标签多. 一种解决方法是采用模板, 在别人写好的骨架内,填入自己的内容.还有一种就是我今天想要介绍的方法----简写法. 常用的简写法,目前主要是Emmet和Haml ... 
- 赵雅智_service电话监听2加接通电话录音
			步骤: 创建CallStateService继承Service 取得电话服务 监听电话动作 电话监听的对象 没有电话时 停止刻录 重设 刻录完毕一定要释放资源 电话响铃时 从麦克风採集声音 内容输出格 ... 
- 选课 - 树型DP(孩子兄弟建树法)
			题目描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了 N(N<300)门的选修课程,每个学生可选课程的数量 M 是给定的.学生选修了这M门课并考核通 ... 
- Java与C#的语法区别
			1.作用域 在java中 { { int a=1; } int a=2;//以上a作用域外的以下,再声明同名的变量,是允许的: } 在C#中,以上是不允许的[只要在同一个作用域内,以上或以下的代码中 ... 
- HDU 4313 Matrix 树形dp
			题意: 给定n个点的树,m个黑点 以下n-1行给出边和删除这条边的费用 以下m个黑点的点标[0,n-1] 删除一些边使得随意2个黑点都不连通. 问删除的最小花费. 思路: 树形dp 每一个点有2个状态 ... 
- Ultra-wideband (UWB) secure wireless device pairing and associated systems
			Methods and systems are disclosed for ultra-wideband (UWB) secure wireless device pairing. Secure pa ... 
- C# 反射调用私有事件
			原文:C# 反射调用私有事件 在 C# 反射调用私有事件经常会不知道如何写,本文告诉大家如何调用 假设有 A 类的代码定义了一个私有的事件 class A { private event EventH ... 
- element-ui 自定义表单验证 , 但是不出现小红心了
			基本上按照文档上提供的方式做就没啥大问题 , 我遇到的问题是 , 自定义以后不显示小红星了 <el-form :model="ruleForm2" status-icon : ... 
- C# 调用PowerShell方法
			PowerShell应为编写和运行都很方便,所以为了重复利用,经常写了一些小方法或者PS代码片段.使用的时候可能会很难找到自己想要的那个方法,如果要是有一个界面把这些代码管理起来并且调用,那就很爽了 ... 
