ArrayList 底层是有数组实现,实际上存放的是对象的引用,而不是对象本身。当使用不带参的构造方法生成ArrayList对象时,实际会在底层生成一个长度为10的数组

当添加元素超过10的时候,会进行扩容 基本上是原来的1.5倍  oldlenth+(oldlenth>>1) 1.5oldlength

>> 表示右移  10>>1(000 1010)右移一位为 5(000 0101)

我们来看下源码

ArrayList a = new ArrayList(); 新建一个arraylist 点进去会出现

 /**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}

  头说明非常清楚,创建一个空的list,初始化他的长度

  /**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; /**
* Shared empty array instance used for empty instances.
*/
private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData;

  DeFAULT_CAPACITY:是某认的长度10

  EMPTY_ELEMENTDATA:是list底层实现的数组

  transient Object[] elementData:存储数组元素的缓冲区,arraylist的容量是这个数组的长度,任何arraylist与elementData=EMPTY_ELEMENTDATA将会被扩展到添加第一个元素时的DEFAULT_CAPACITY

  

  transient关键字 修饰 表示在序列化的时候,被修饰的不会被序列化。

但是在arraylist中不是这样的,arraylist实现了序列化的writeObject()可指定序列化,arrayList将强制把elementData序列化,但是arryaList内部序列化的时候,因为初始

容量有10 ,但是我可能只有5个元素,那么剩下的就会是空值,在序列化的时候会把空值序列化进去,那么就没有意义,如果直接标记序列化则会把空值序列化进去,用transient修饰后然后重写writeObject()方法将其序列化,只序列化存储元素而不是整个数组,这样可以降低序列化的传输量,从而来提示速度

 /**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size); // Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
} if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

  这里会去根据size的长度去遍历,然后将对应值取出来序列化

boolean add方法 是将改对象加入到数据的最末端

void add(int index,E element)方法则是要从指定位置+1开始往后使用arraycopy方法赋值数组操作,之后在对对应元素赋值

void add方法

 /**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
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++;
}

boolean add方法

  /**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}

我们来一句一句的分析

进入add方法首先就是ensureCapacityInternal(size+1)设置内部缓冲区,在当前基础上+1,然后将元素添加到数组中

ensureCapacity()方法

  首先会判断数组对象是不是初始化数组,如果是的话,则会用初始化值也就是默认的长度10和我们现在传给他的长度做对比

如果传给他的值大于10则minCapacity最小容量为传的值,反之则为10.然后去设置缓冲区大小进入 ensureExplicitCapacity(minCapacity);

ensureExplicitCapacity(minCapacity)

  首先 modCount会自增,然后判断传过来的最知晓容量是否大于现有数组的长度,如果大于则扩容进入grow(minCapacity)方法

gorw(minCapacity)

   方法中,会想当前数组的长度基础上右移一位然后加上当前数组的长度相当于1.5倍,然后用新得到的长度和最小容量去对比

如果小于最小容量,则新容量为最小容量,反正则不变。然后新容量会和list最大长度对比,如果他比list最大值还大则返回默认定义的MAX_VALUE

最后调用copy方法进行赋值

本文初次读源码。。里面可能会有很多错误或者意思描述不清的地方,希望大家指出来,我好改正以免误导别人。。。大家一起共同学习进步

ArrayList底层实现的更多相关文章

  1. ArrayList底层原理

    ArrayList底层采用数组实现,访问特别快,它可以根据索引下标快速找到元素.但添加插入删除等写操作效率低,因为涉及到内存数据复制转移. ArrayList对象初始化时,无参数构造器默认容量为10, ...

  2. 模拟ArrayList底层实现

    package chengbaoDemo; import java.util.ArrayList; import java.util.Arrays; import comman.Human; /** ...

  3. ArrayList底层实现原理

    ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现列表接口外,此类还提供一些方法来操作内部用来存储列表的数组 ...

  4. ArrayList 底层实现原理

    ArrayList的底层实现原理 1, 属性:private static final int DEFAULT_CAPACITY = 10; private static final Object [ ...

  5. JAVA SE ArrayList 底层实现

    Array 查询效率高,增删效率低( Link 增删效率高 Vector 线程安全 List 列表 源代码: package com.littlepage.test; /** * 基于底层实现Arra ...

  6. Java——ArrayList底层源码分析

    1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...

  7. ArrayList底层代码解析笔记

    通过底层代码可以学习到很多东西: public class ArrayList<E> extends AbstractList<E> implements List<E& ...

  8. Java ArrayList底层实现原理源码详细分析Jdk8

    简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用 ...

  9. ArrayList、LinkedList、HashMap底层实现

    ArrayList 底层的实现就是一个数组(固定大小),当数组长度不够用的时候就会重新开辟一个新的数组,然后将原来的数据拷贝到新的数组内. LinkedList 底层是一个链表,是由java实现的一个 ...

随机推荐

  1. bzoj 2238 Mst

    显然先求出最小生成树 如果删的是非树边就不用管,还是能取最小生成树 如果删的是树边就有非树边可以替代它 反向考虑,每条非树边可以替代最小生成树上一条路径的边 所以树剖加线段树,对每条非树边在树上更新对 ...

  2. 日常的例子说明 throttle 和 debounce 的区别

    不小心接触到 throttle 和 debounce,按捺不住猎奇的心理,找这两个函数的资料. 然而百度到的各种对他们的理解,我去啊. 艰难地搞明白他们是干嘛的之后,忍不住举个例子说说自己的理解,希望 ...

  3. jQuery插件编写基础之“又见弹窗”

    本文将通过一个实例来引出jQuery插件开发中的一些细节,首先介绍下jQuery插件开发的一些基础知识. jQuery的插件开发主要分为两类: 1. 类级别,即在jQuery类本身上扩展方法,类似与 ...

  4. VB.NET 仿Edge风格的TabControl控件

    原本是想写个Chrome内核的浏览器,但是.net语言下比较好用类库的并不多,尝试过CefSharp.Xilium.CefGlue,都发现很多坑,所以这个项目就烂尾了,现在将还有点用的代码发出来给大家 ...

  5. Mysql行转列的简单应用

    最近在复习过程中愈发觉得,有些东西久了不用,真的会忘~——~. 将上面的表格转换为下面的表格 我拼sql拼了好久还是没弄出来,还是偶然看到我以前的笔记,才想起有行转列这样的操作(太久没有写过复杂点的s ...

  6. SQL知识点脑图(一张图总结SQL)

    sql语言的分类DDL:create drop alter DML:insert delete update DCL:rollback grant revoke commit 概要,主外键,视图,索引 ...

  7. Keycloak服务器安装和配置

    安装地址:https://www.keycloak.org/archive/downloads-4.4.0.html 参考文档:https://www.keycloak.org/docs/latest ...

  8. Linux命令之mount挂载

    挂载概念 Linux中的根目录以外的文件要想被访问,需要将其“关联”到根目录下的某个目录来实现,这种关联操作就是“挂载”,这个目录就是“挂载点”,解除次关联关系的过程称之为“卸载”. 注意:“挂载点” ...

  9. [整理]CHttpConnection的使用

    使用步骤: 1.构造一个CInternetSession的实例 CInternetSession* pSession =new CinternetSession(); //CInternetSessi ...

  10. jenkins部署时遇到“似乎无法联网”,导致无法安装默认插件的解决方案

    jenkins安装更新时,默认会检查网络连接,而默认的checkulr 是http://www.google.com/ ,国内是无法访问的,所以修改成任意可以访问的地址即可,比如http://www. ...