ArrayList源码分析(基于JDK1.8)
- public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
从ArrayList<E>可以看出它是支持泛型的,它继承自AbstractList,实现了List、RandomAccess、Cloneable、java.io.Serializable接口。
AbstractList提供了List接口的默认实现(个别方法为抽象方法)。
List接口定义了列表必须实现的方法。
RandomAccess是一个标记接口,接口内没有定义任何内容。
实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。
通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。
ArrayList几个重要的字段属性
- 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 = {};
- // 存储ArrayList的元素
- transient Object[] elementData; // non-private to simplify nested class access
- /**
- * The size of the ArrayList (the number of elements it contains).
- *
- * @serial
- */
- // elementData指示elementData包含的元素的数量
- private int size;
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList的构造方法:
- public ArrayList(int initialCapacity) {
- if (initialCapacity > 0) {
- this.elementData = new Object[initialCapacity];
- } else if (initialCapacity == 0) {
- // this.elementData = {};
- this.elementData = EMPTY_ELEMENTDATA;
- } else {
- throw new IllegalArgumentException("Illegal Capacity: "+
- initialCapacity);
- }
- }
- /**
- * Constructs an empty list with an initial capacity of ten.
- */
- public ArrayList() {
- this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
- }
- // 使用集合来初始化
- public ArrayList(Collection<? extends E> c) {
- elementData = c.toArray();
- if ((size = elementData.length) != 0) {
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
- if (elementData.getClass() != Object[].class)
- elementData = Arrays.copyOf(elementData, size, Object[].class);
- } else {
- // replace with empty array.
- this.elementData = EMPTY_ELEMENTDATA;
- }
- }
第一个构造方法:根据指定容量进行构造elementData数组。
第二个无参构造方法:初始化为{},size也为0.当执行add操作的时候,如果为{},则将其容量初始化为DEFAULT_CAPACITY,即为10
第三个构造方法:将集合对象转换成Object数组。Arrays的方法在另一篇博文将做分析。
其它方法:
add(E e):
- public boolean add(E e) {
- // 扩容
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
- private void ensureCapacityInternal(int minCapacity) {
- ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
- }
- private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果elementData为空,则初始化为DEFAULT_CAPACITY- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- return Math.max(DEFAULT_CAPACITY, minCapacity);
- }
- return minCapacity;
- }
- private void ensureExplicitCapacity(int minCapacity) {
- modCount++;
- // overflow-conscious code , 如果扩容大于elementData容量,进行扩容。
- if (minCapacity - elementData.length > 0)
- grow(minCapacity);
- }
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- // newCapacity = oldCapacity * 1.5 扩大为之前的1.5倍。
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity < 0)
- // 如果扩容后,newCapacity还是小于minCapacity,则直接赋值为minCapacity
- newCapacity = minCapacity;
// 如果1.5 * elementData.length比Integer.MAX_VALUE - 8还大- 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);
- }
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
// 如果minCapacity即为Array.length大于Integer.MAX_VALUE - 8. 则直接赋为Integer.MAX_VALUE , 否则就为MAX_ArraySIZE- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
为什么是1.5倍扩容呢?
- public boolean addAll(Collection<? extends E> c)
先将集合c转换成数组,根据转换后数组的程度和ArrayList的size拓展容量,之后调用System.arraycopy方法复制元素到elementData的尾部,调整size。根据返回的内容分析,只要集合c的大小不为空,即转换后的数组长度不为0则返回true。
- public boolean addAll(int index, Collection<? extends E> c)
先判断index是否越界。其他内容与addAll(Collection<? extends E> c)基本一致,只是复制的时候先将index开始的元素向后移动X(c转为数组后的长度)个位置(也是一个复制的过程),之后将数组内容复制到elementData的index位置至index+X。
clear的时候并没有修改elementData的长度(好不容易申请、拓展来的,凭什么释放,留着搞不好还有用呢。这使得确定不再修改list内容之后最好调用trimToSize来释放掉一些空间),只是将所有元素置为null,size设置为0。
- public void clear() {
- modCount++;
- // clear to let GC do its work
- for (int i = 0; i < size; i++)
- elementData[i] = null;
- size = 0;
- }
返回此 ArrayList 实例的浅表副本。(不复制这些元素本身。),如果是对象,只是复制引用。
- public Object clone() {
- try {
- ArrayList<?> v = (ArrayList<?>) super.clone();
- v.elementData = Arrays.copyOf(elementData, size);
- v.modCount = 0;
- return v;
- } catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError(e);
- }
- }
indexOf:通过遍历elementData数组来判断对象是否在list中,若存在,返回元素下标的位置。时间复杂度是O(n)
- public int indexOf(Object o) {
- if (o == null) {
- for (int i = 0; i < size; i++)
- if (elementData[i]==null)
- return i;
- } else {
- for (int i = 0; i < size; i++)
- if (o.equals(elementData[i]))
- return i;
- }
- return -1;
- }
lastIndexOf:从后向前遍历。
remove:
- public E remove(int index) {
- rangeCheck(index);
- modCount++;
- E oldValue = elementData(index);
- int numMoved = size - index - 1;
- if (numMoved > 0)
- // 从index+1开始的元素复制到elementData中从index下标开始,总共有numMoved个元素。
- System.arraycopy(elementData, index+1, elementData, index,
- numMoved);
- elementData[--size] = null; // clear to let GC do its work
- return oldValue;
- }
- public boolean remove(Object o) {
- if (o == null) {
- for (int index = 0; index < size; index++)
- if (elementData[index] == null) {
- // fastRemove基本和remove的代码一致,只是不用进行边界判断。
- fastRemove(index);
- return true;
- }
- } else {
- for (int index = 0; index < size; index++)
- if (o.equals(elementData[index])) {
- fastRemove(index);
- return true;
- }
- }
- return false;
- }
ArrayList源码分析(基于JDK1.8)的更多相关文章
- ArrayList 源码分析 基于jdk1.8:
1:数据结构: transient Object[] elementData; //说明内部维护的数据结构是一个Object[] 数组 成员属性: private static final int ...
- HashMap 源码分析 基于jdk1.8分析
HashMap 源码分析 基于jdk1.8分析 1:数据结构: transient Node<K,V>[] table; //这里维护了一个 Node的数组结构: 下面看看Node的数 ...
- CopyOnWriteArrayList 源码分析 基于jdk1.8
CopyOnWriteArrayList 源码分析: 1:成员属性: final transient ReentrantLock lock = new ReentrantLock(); //内部是 ...
- ArrayList 源码分析(JDK1.8)
ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess ...
- ArrayList源码分析(JDK1.8)
概述 ArrayList底层是基于数组实现的,并且支持动态扩容的动态数组(变长的集合类).ArrayList允许空值和重复的元素,当向ArrayList中添加元素数量大于其底层数组容量时,会通过扩容机 ...
- HashMap源码分析-基于JDK1.8
hashMap数据结构 类注释 HashMap的几个重要的字段 hash和tableSizeFor方法 HashMap的数据结构 由上图可知,HashMap的基本数据结构是数组和单向链表或红黑树. 以 ...
- ArrayList的源码分析(基于jdk1.8)
1.初始化 transient Object[] elementData; //实际存储元素的数组 private static final Object[] DEFAULTCAPACITY_EMPT ...
- LinkedList的源码分析(基于jdk1.8)
1.初始化 public LinkedList() { } 并未开辟任何类似于数组一样的存储空间,那么链表是如何存储元素的呢? 2.Node类型 存储到链表中的元素会被封装为一个Node类型的结点.并 ...
- ArrayList源码解读(jdk1.8)
概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...
- ArrayList源码分析--jdk1.8
ArrayList概述 1. ArrayList是可以动态扩容和动态删除冗余容量的索引序列,基于数组实现的集合. 2. ArrayList支持随机访问.克隆.序列化,元素有序且可以重复. 3. ...
随机推荐
- nginx与apache 对比 apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
nginx与apache详细性能对比 http://m.blog.csdn.net/lengzijian/article/details/7699444 http://www.cnblogs.com/ ...
- XMU 1615 刘备闯三国之三顾茅庐(三) 【欧拉函数+快速幂+欧拉定理】
1615: 刘备闯三国之三顾茅庐(三) Time Limit: 1000 MS Memory Limit: 128 MBSubmit: 45 Solved: 8[Submit][Status][W ...
- +Java中的native关键字浅析(Java+Native+Interface)++
JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...
- 高清摄像头MIPI CSI2接口浅解【转】
本文转载自:http://blog.csdn.net/u012075739/article/details/44672435 MIPI摄像头常见于手机.平板中,支持500万像素以上高清分辨率.它的全称 ...
- silverlight DataGrid 显示篇
silverlight DataGrid 显示篇 分类: Silverlight2012-05-12 21:55 693人阅读 评论(0) 收藏 举报 datagridsilverlightbindi ...
- Masonry 比例(multipliedBy)
前言 说到iOS自动布局,有很多的解决办法.有的人使用xib/storyboard自动布局,也有人使用frame来适配.对于前者,笔者并不喜欢,也不支持.对于后者,更是麻烦,到处计算高度.宽度等,千万 ...
- iOS开发,#define的使用
1.判断当前设备是不是iOS7以上版本 #define IOS_VERSION_7_OR_ABOVE (([[[UIDevice currentDevice] systemVersion] float ...
- jquery中跳出each循环
or循环 VS jquery.each continue return true break return false
- Jmeter测试接口
文主要针对http接口进行测试,使用Jmeter工具实现. Jmter工具设计之初是用于做性能测试的,它在实现对各种接口的调用方面已经做的比较成熟,因此,本次直接使用Jmeter工具来完成对Http接 ...
- CCF2016.4 - A题
思路:枚举每个点,看看它是否同时小于/大于前一个点和后一个点 import java.util.Scanner; public class Main { public static void main ...