ArrayList源码阅读.

//测试代码实现如下
private static void arrayList() {
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add(1, null);
int size = list.size();
for (int i = 0; i < size; i++) {
System.out.println(list.get(i));
}
}

查看ArrayList<String>();的源码的时候可以发现如下:

  1. 其属性elementData被初始化为一个空的Object数组.
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

执行list.add("aaa");可以看到如下源码:

  1. 其中的size表示目前List中已经存储的元素的数量,目前为0.

  2. 开始执行添加元素操作.add(e, elementData, size);

protected transient int modCount = 0;
transient Object[] elementData; // non-private to simplify nested class access
private int size;
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}

进入add(e, elementData, size);可以看到如下源码:

  1. 已存储元素和当前的对象数组的长度相等,都是0.

  2. 执行数组扩容行动elementData = grow();

  3. 当目前对象数组已满时得到,size==elementData.length.

  4. 进入elementData = grow();,继续扩容.

  5. 通过最后两行代码给对象数组赋值.

private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}

进入elementData = grow();可以看到如下源码:

  1. grow()函数 调用grow(int minCapacity)函数,其中传参的值,是目前需要的最小空间值.

  2. 在经过newCapacity的计算之后将 新的对象数组的值,copy到elementData中.由此便完成了第一次扩容.

  3. 最小值更新minCapacity为11

private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private Object[] grow() {
return grow(size + 1);
}

进入newCapacity(minCapacity)可以看到如下源码:

  1. oldCapacity旧容量的值设置为对象数组的长度,newCapacity新容量的值设置为老容量+老容量的一次右移运算.

  2. 操作了半个小时结果发现newCapacity为0,然后进入if循环,发现目前的elementData一点没动,其地址还是最初的时候赋值的DEFAULTCAPACITY_EMPTY_ELEMENTDATA.

  3. 在默认容量DEFAULT_CAPACITY=10和最小容量minCapacity=1之间选择一个最大值,也就是10.作为返回值.

  4. newCapacity在经过右移运算后为15 . 然后执行就以15为最新的扩容值为准 返回.

private static final int DEFAULT_CAPACITY = 10;
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}


Vector的源码和ArrayList对比只有一点的不同, 那就是Vector在添加元素的时候加了线程锁, 是线程安全的.

public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}

总结: 其实就是扩容的操作解读, 赋值很简单. 而且源码的条例就是比我们自己写的好得多.

JDK12下的ArrayList源码解读 与 Vector的对比的更多相关文章

  1. ArrayList 源码解读

    ArrayList 源码解读     基于JDk 1.7.0_80 public class ArrayList<E> extends AbstractList<E> impl ...

  2. ArrayList源码解读(jdk1.8)

    概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...

  3. 深入理解JAVA集合系列四:ArrayList源码解读

    在开始本章内容之前,这里先简单介绍下List的相关内容. List的简单介绍 有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制.用户可以根据元素的整数索引(在列表中的位置) ...

  4. Java集合ArrayList源码解读

    最近在回顾数据结构,想到JDK这样好的代码资源不利用有点可惜,这是第一篇,花了心思.篇幅有点长,希望想看的朋友认真看下去,提出宝贵的意见.  :) 内部原理 ArrayList 的3个字段 priva ...

  5. ArrayList源码解读笔记

    简介: ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高. 线 ...

  6. Java集合(四)--基于JDK1.8的ArrayList源码解读

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  7. java集合之ArrayList源码解读

    源自:jdk1.8.0_121 ArrayList继承自AbstractList,实现了List.RandomAccess.Cloneable.Serializable. ArrayList内部是通过 ...

  8. ArrayList源码解读

    在端午节这个节日里,有一个特殊的任务,我带着你一起揭开"ArrayList"的真面目.从成员变量.构造函数.主要方法三部分,对ArrayList有进一步的认识,希望能够帮助你. 一 ...

  9. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

随机推荐

  1. 使用valgrind进行内存泄漏和非法内存操作检测

    valgrind是一个强大的工具,最常用的功能是用它来检测内存泄漏和非法内存的使用.要想让valgrind报告的更加细致,请使用-g进行编译. 基本命令如下: $ valgrind --tool=me ...

  2. u盘安装debian 7(Wheezy) stabe

    将一个闲置u盘插入电脑usb口.从http://mirrors.sohu.com/debian-cd/7.4.0/amd64/iso-dvd/debian-7.4.0-amd64-DVD-1.iso ...

  3. Spring Boot2.0之 yml的使用

    yml Spring Boot 默认读取   .yml   .properties 结尾的 yml非常好的作用,比properties更节约  结构清晰 server: port:  8090 con ...

  4. Android SDK和NDK

    NDK是用来给安卓手机开发软件用的,但是和SDK不同的是它用的是C语言,而SDK用的是Java语言.NDK开发的软件在安卓的环境里是直接运行的,一般只能在特定的CPU指令集的机器上运行,而且C语言可以 ...

  5. tensorflow实现svm多分类 iris 3分类——本质上在使用梯度下降法求解线性回归(loss是定制的而已)

    # Multi-class (Nonlinear) SVM Example # # This function wll illustrate how to # implement the gaussi ...

  6. LNMP安装(一)

    前传: 环境介绍: Centos7.2-minimal 下载地址:http://mirrors.163.com/centos/7.2.1511/isos/x86_64/ (网易镜像站) 所需安装包:链 ...

  7. Seq2SQL :使用强化学习通过自然语言生成SQL

    论文: https://einstein.ai/static/images/layouts/research/seq2sql/seq2sql.pdf  数据集:https://github.com/s ...

  8. 使用google浏览器模拟手机终端的方法

    谷歌Chrome浏览器,可以很方便地用来当移动终端模拟器.在Windows的[开始]-->[运行]中输入以下命令,启动谷歌浏览器,即可模拟相应手机的浏览器去访问3G手机网页,前提:将先前开启的谷 ...

  9. 【LeetCode】259 3Sum Smaller

    题目: Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 ...

  10. select查询语句执行顺序

    查询中用到的关键词主要包含六个,并且他们的顺序依次为select--from--where--group by--having--order by其中select和from是必须的,其他关键词是可选的 ...