一、概述

ArrayList 是一个动态数组,实现了 List 接口以及 list相关的所有方法,它允许所有元素的插入,包括 null。另外,ArrayList 和 Vector 除了线程不同步之外,大致相等。

二、属性

ArrayList 的属性非常少,就只有这些。其中最重要的莫过于 elementData ,ArrayList所有的方法都是建立在 elementData 之上

/*** 默认容量大小*/private static final int DEFAULT_CAPACITY = 10;/*** 空数组常量*/private static final Object[] EMPTY_ELEMENTDATA = {};/*** 默认的空数组常量*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 存放元素的数组,可以发现ArrayList的底层实现是一个Object数组*/transient Object[] elementData; /*** 数组中包含的元素个数*/private int size;/***数组的最大上限*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

三、方法

1、构造方法

从构造方法中我们可以看见,默认情况下,elementData 是一个大小为0的空数组,当我们指定了初始大小的时候,elementData 的初始大小就变成了我们所指定的初始大小了

public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

2、 get方法

因为ArrayList是采用数组结构来存储的,所以它的get 方法非常简单,先是判断一下有没有越界,之后就可以直接通过数组下标来获取元素了,所以 get 的时间复杂度是 O(1)

public E get(int index) {rangeCheck(index);return elementData(index);
}
// 判断是否存在数组越界访问的问题
private void rangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}//根据下标获取数据
E elementData(int index) {return (E) elementData[index];
}

3、add方法

public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1);  // Increments modCount!!//调用一个 native 的复制方法,把 index 位置开始的元素都往后挪一位System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;}private void ensureCapacityInternal(int minCapacity) {// 如果当 elementData 为空数组时,它会使用默认的大小去扩容if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}// 检查是否需要扩容private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}
  • ArrayList的add方法:在插入元素之前,它会先检查是否需要扩容,然后再把元素添加到数组中最后一个元素的后面。在ensureCapacityInternal方法中,我们可以看见,如果当elementData为空数组时,它会使用默认的大小去扩容。所以说,通过无参构造方法来创建 ArrayList时,它的大小其实是为0的,只有在使用到的时候,才会通过grow方法去创建一个大小为10的数组
  • 第一个add方法的复杂度为O(1),虽然有时候会涉及到扩容的操作,但是扩容的次数是非常少的,所以这一部分的时间可以忽略不计。如果使用的是带指定下标的add方法,则复杂度为 O(n),因为涉及到对数组中元素的移动,这一操作是非常耗时的。

4、set方法

set方法的作用是把下标为index的元素替换成element,跟get非常类似,时间复杂度度为 O(1)

public E set(int index, E element) {rangeCheck(index);E oldValue = elementData(index);elementData[index] = element;return oldValue;}private void rangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}

5、remove方法

remove 方法与 add 带指定下标的方法非常类似,也是调用系统的 arraycopy 方法来移动元素,时间复杂度为 O(n)

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 workreturn oldValue;}

6、grow方法

grow方法是在数组进行扩容的时候用到的,从中我们可以看见,ArrayList 每次扩容都是扩1.5 倍,然后调用Arrays类的copyOf方法,把元素重新拷贝到一个新的数组中去

private void grow(int minCapacity) {// overflow-conscious codeint 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);}

7、size方法

size 方法非常简单,它是直接返回 size 的值,也就是返回数组中元素的个数,时间复杂度为 O(1)。这里要注意一下,返回的并不是数组的实际大小

public int size() {return size;}

8、indexOf方法和LastIndexOf方法

  • indexOf方法的作用是返回第一个等于给定元素的值的下标。它是通过遍历比较数组中每个元素的值来查找的,所以它的时间复杂度是 O(n)
  • lastIndexOf的原理跟indexOf一样,而它仅仅是从后往前找起
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;}public int lastIndexOf(Object o) {if (o == null) {for (int i = size-1; i >= 0; i--)if (elementData[i]==null)return i;} else {for (int i = size-1; i >= 0; i--)if (o.equals(elementData[i]))return i;}return -1;}

四、Vector

Vector很多方法都跟ArrayList一样,只是多加了个synchronized来保证线程安全

Vector 比 ArrayList 多了一个属性:

protected int capacityIncrement;

这个属性是在扩容的时候用到的,它表示每次扩容只扩 capacityIncrement 个空间就足够了。该属性可以通过构造方法给它赋值。先来看一下构造方法:

public Vector(int initialCapacity, int capacityIncrement) {super();if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);this.elementData = new Object[initialCapacity];this.capacityIncrement = capacityIncrement;}public Vector(int initialCapacity) {this(initialCapacity, 0);}public Vector() {this(10);}

从构造方法中,我们可以看出 Vector 的默认大小也是 10,而且它在初始化的时候就已经创建了数组了,这点跟 ArrayList 不一样。再来看一下 grow 方法:

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);}

从 grow 方法中我们可以发现,newCapacity 默认情况下是两倍的 oldCapacity,而当指定了 capacityIncrement 的值之后,newCapacity 变成了oldCapacity+capacityIncrement。

五、总结

  1. ArrayList 创建时的大小为 0;当加入第一个元素时,进行第一次扩容时,默认容量大小为 10
  2. ArrayList 每次扩容都以当前数组大小的 1.5 倍去扩容
  3. Vector 创建时的默认大小为 10
  4. Vector 每次扩容都以当前数组大小的 2 倍去扩容。当指定了 capacityIncrement 之 后,每次扩容仅在原先基础上增加 capacityIncrement 个单位空间
  5. ArrayList 和 Vector 的 add、get、size 方法的复杂度都为 O(1),remove 方法的复杂度为 O(n)
  6. ArrayList 是非线程安全的,Vector 是线程安全的

Java8的集合:ArrayList的实现原理相关推荐

  1. ava集合---ArrayList的实现原理

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

  2. 深入Java集合学习系列:ArrayList的实现原理

    参考文献 深入Java集合学习系列:ArrayList的实现原理 本文转自xwdreamer博客园博客,原文链接:http://www.cnblogs.com/xwdreamer/archive/20 ...

  3. Java集合—ArrayList底层原理

    原文作者:0 errors 0 warnings 原文地址:用大白话告诉你ArrayList的底层原理 目录 一.数据结构 二.线程安全性 三.继承关系 四.构造方法 五.add()方法 六.扩容机制 ...

  4. 考考基础部分,谈谈Java集合中HashSet的原理及常用方法

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:工匠初心 cnblogs.com/LiaHon/p/1125 ...

  5. Java ArrayList的实现原理详解

    ArrayList是Java List类型的集合类中最常使用的,本文基于Java1.8,对于ArrayList的实现原理做一下详细讲解. (Java1.8源码:http://docs.oracle.c ...

  6. java集合-ArrayList

    java集合 ArrayList Iterable Comparable(排序接口) 项目结构: class Dog implements Comparable<Dog> {private ...

  7. Java ArrayList和Vector、LinkedList与ArrayList、数组(Array)和列表集合(ArrayList)的区别...

    ArrayList和Vector的区别 ArrayList与Vector主要从二方面来说. 一.同步性: Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的. ...

  8. Java之List系列--ArrayList扩容的原理

    原文网址:Java之List系列--ArrayList扩容的原理_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java的ArrayList是如何进行扩容的.即:扩容的机制. 重要大小 类 初 ...

  9. C#方法,可空类型,数组,集合,ArrayList排序,List,Hashtable和Dictionary

    C#方法 方法的定义: public void/int Compare(int a,int b){ } Program program = new Program(); Console.WriteLi ...

  10. 第九天 (集合 ArrayList)

    目录 集合 ArrayList 创建集合的对象 ArrayList成员方法 集合 集合和数组的对比 1.长度: 集合自动伸缩,可长可短,自动扩容. 数组长度固定. 2.存储类型: 集合可以存储引用数据 ...

最新文章

  1. 设置select下拉框不可修改的→“四”←种方法
  2. 微擎删除分类无法删除解决-select in效率低解决办法
  3. 从MSSQL添加对Oracle的链接服务器的存储过程
  4. 顶级项目管理工具 Top 10
  5. mongodb简介、安装、启停(转并学习)
  6. spring boot自定义配置文件
  7. 菜鸟教程-css学习笔记
  8. C语言代码规范(五)函数参数个数
  9. jQuery 表单验证插件 jQuery Validation Engine 使用
  10. EventBus,轻松实现跨组件跨线程通信
  11. cp命令显示进度条_教程 | Linux常用命令大全
  12. 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。...
  13. 【我为车狂性感车模win7主题】
  14. 最好用的WiFi密码共享APP推荐(能查看已连接WiFi密码)
  15. 利用高德云图开发附近的人功能
  16. Pymoo:优化算法收敛性的实例分析
  17. 四轴笔记----PSRAM存储器介绍
  18. 名帖292 张瑞图 行书《论书卷》
  19. 手板(prototype)
  20. 预付费售电管理系统的构建及应用

热门文章

  1. 你们都是怎么学 Python 的?
  2. c++ 类数组_输入输出流IO体系及常用类关系结构(精要收藏)
  3. Linux之Vim文本代码编辑神器应用get技巧
  4. LINUX按照物理地址预取,linux – 如何以编程方式禁用硬件预取?
  5. unix oracle控制台,Linux平台下启动oracle11gEM控制台
  6. 指针 混用 迭代器_对比 C++ 和 Python,谈谈指针与引用
  7. C语言----字符串左旋
  8. 线段树区间扫描线超详解,一篇文章搞懂扫描线
  9. xp系统本地连接服务器,本地连接,xp系统本地连接不见了怎么办
  10. 循环小数是分数集合吗_2020年部分CFA国外考场取消,通过率会受影响吗?