【集合框架】JDK1.8源码分析之ArrayList详解(一)

一. 从ArrayList字表面推测

ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,List的中文意思是列表。从ArrayList字表面推测,ArrayList类是否有数组和列表的特征?那么,这些特征这在ArrayList类中又是怎么体现的?

ArrayList源码分析

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

从上面的代码可知道,以下几点

  1. 继承了AbstractList类,实现了List,意味着ArrayList是一个数组队列,提供了诸如增删改查、遍历等功能。
  2. 实现了RandomAccess接口,意味着ArrayList提供了随机访问的功能。RandomAccess接口在Java中是用来被List实现,用 来提供快速访问功能的。在ArrayList中,即我们可以通过元素的序号快速获取元素对象。
  3. 实现了Cloneable接口,意味着ArrayList实现了clone()函数,能被克隆。
  4. 实现了java.io.Serializable接口,意味着ArrayList能够通过序列化进行传输。

    ArrayList的属性

    /**
     * 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; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;
  • DEFAULT_CAPACITY :默认容量大小为10。
  • EMPTY_ELEMENTDATA :用于Constructs有参数传入,如果参数等于零,则使用该属性。
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA :用于Constructs无参数传入默认大小为10(具体运用于add中),使用使用该属性。
  • size :当前容量大小

## 构造分析
### 有参数构造Method
传入initialCapacity参数,如果参数大于零,创建一个大小为initialCapacity的数组
/** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //new一个大小为initialCapacity的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }

无参数构造Method

里面只有一个操作就是把 elementData 设置为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 这个空数组。

// 无参的构造函数,传入一个空数组  这时候会创建一个大小为10的数组,具体操作在 add 中
 public ArrayList() {
 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }

增删查改Method

add Method

这个方法首先调用了 ensureCapacityInternal() 这个方法里面就判断了当前的 elementData 是否等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 如果是的话,就把数组的大小设置为 10 然后进行扩容操作,这里刚好解释了为什么采用无参构造的List 的大小是 10 ,这里扩容操作调用的方法是 ensureExplicitCapacity 里面就干了一件事如果用户指定的大小 大于当前长度就扩容,扩容的方法采用了 Arrays.copy 方法,这个方法实现原理是 new 出一个新的数组,然后调用 System.arraycopy 拷贝数组,最后返回新的数组。

public boolean add(E e) {
 // 当调用了无参构造,设置大小为10
 ensureCapacityInternal(size + 1);  // Increments modCount
 elementData[size++] = e;
 return true;
}  

private void ensureCapacityInternal(int minCapacity) {
 // 如果当前数组是默认空数组就设置为 10和 size+1中的最小值
 // 这也就是说为什么说无参构造 new 的数组大小是 10
 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
 }  

 ensureExplicitCapacity(minCapacity);
}  

private void ensureExplicitCapacity(int minCapacity) {
 modCount++;  

 // 若用户指定的最小容量 > 最小扩充容量,则以用户指定的为准,否则还是 10
 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);
}

Remove Method

通过index知道位置,然后index位置的值被index+1位置的值往前覆盖,覆盖的次数为size - index - 1

/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    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;
    }

get Method

通过index 来访问元素

public E get(int index) {
            //检测范围
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }
 

set Method

通过index知道要修改的元素并替换了

  public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
           

【集合框架】JDK1.8源码分析之ArrayList详解(一)的更多相关文章

  1. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  2. 【集合框架】JDK1.8源码分析之ArrayList(六)

    一.前言 分析了Map中主要的类之后,下面我们来分析Collection下面几种常见的类,如ArrayList.LinkedList.HashSet.TreeSet等.下面通过JDK源码来一起分析Ar ...

  3. vuex 源码分析(六) 辅助函数 详解

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  4. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

  5. Golang源码分析之目录详解

    开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...

  6. Java 容器源码分析之集合类详解

    集合类说明及区别 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └W ...

  7. Tomcat源码分析 | 一文详解生命周期机制Lifecycle

    目录 什么是Lifecycle? Lifecycle方法 LifecycleBase 增加.删除和获取监听器 init() start() stop() destroy() 模板方法 总结 前言 To ...

  8. Cloudera Impala源码分析: SimpleScheduler调度策略详解包括作用、接口及实现等

    问题导读:1.Scheduler任务中Distributed Plan.Scan Range是什么?2.Scheduler基本接口有哪些?3.QuerySchedule这个类如何理解?4.Simple ...

  9. 【集合框架】JDK1.8源码分析之HashMap(一) 转载

    [集合框架]JDK1.8源码分析之HashMap(一)   一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...

随机推荐

  1. SQL优化 MySQL版 - B树索引详讲

    SQL优化 MySQL版  - -B树索引详讲 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 为什么要进行SQL优化呢?很显然,当我们去写sql语句时: 1会发现性能低 2.执行时间太 ...

  2. Server Error in '/' Application Runtime Error 错误

    项目发布后  在本地发布可以运行  在服务器就会出现这种错误 在网上也查找了各种资料  解决方案 都没有解决 因为我用的C# 首先在 Webconfig配置文件中的 system.web中加入 < ...

  3. c# 接口相同方法申明使用

    using System; namespace ConsoleApp1 { interface IInterface1 { void ft(); } interface IInterface2 { v ...

  4. 【swoole】如果使用好定时器功能

    swoole中提供了一个定期器的用法 $server->tick(1000, function() use ($server, $fd) { $server->send($fd, &quo ...

  5. Install Windows 2016 on VirtualBox

    Download ISO file for Windows 2016 (180 days free).  https://www.microsoft.com/en-us/evalcenter/eval ...

  6. Windows Server 2016-Netdom Join之客户端加域(二)

    上章节我们介绍了如何通过图形化界面实现用户加域操作,本章节为大家简单介绍如何通过netdom join命令实现计算机加域操作.具体信息如下: 将工作站或成员服务器加入域.将计算机加入域的行为会为域中的 ...

  7. OKR能解决996吗?德鲁克怎么看?

    最近网络上热议的“996”,不由让人想起我们的邻国日本.他们在20年前就有过一个热词“过劳死”,就是职场加班太严重导致的猝死. 最近有一本书新书<过劳时代>,说的就是日本20年前的过劳死. ...

  8. kafka监控项目大全

    https://github.com/claudemamo/kafka-web-console   http://github.com/pinterest/doctorkafka   http://g ...

  9. CentOS7 使用firewalld打开关闭防火墙与端口

    1.firewalld的基本使用 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status f ...

  10. C# Npoi 实现Excel与数据库相互导入

    十年河东,十年河西,莫欺少年穷! NPOI支持对 Word 和 Excel 文件的操作! 针对 Word 的操作一般用于打印技术!说白了就是利用 Word 文件作为模板,生成各种不同的打印!具体用到的 ...