java中ArrayList的源码实现
来源:互联网 发布:asc软件 编辑:程序博客网 时间:2024/06/09 17:26
java中的ArrayList底层是通过数组实现的,下面是我对ArrayList源码阅读之后整理并添加了注释之后的整理,为了方便,就只贴出ArrayList的add方法以及它的一些思想还有边界条件处理:
public class ArrayList<E> implements List<E> { private Object[] elementData;//存储数据的数组 private int size;//数组的当前个数 而不是最大个数 private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //为什么最大是2^31-8? As the Array itself needs 8 bytes to stores the size 2147483648(原文) private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8; private boolean RangeCheck(int index){ return (index>-1)&&(index<size); } //保证newSize不会越界 将集合的capacity增加到minCapacity minCapacity为所需最小容量 //采用的思路和jdk中源码思路类似 如果不足则添加原来容量的一半 用移位来实现 public void ensureCapacity(int minCapacity) { //如果elementData为空 最小扩展到10 如果不为空 最小扩展到0 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0:DEFAULT_CAPACITY; if(minCapacity>minExpand){ ensureExplicitCapacity(minCapacity); } } private void ensureCapacityInternal(int minCapacity){ if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA){ minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } //确保明确的容器 private void ensureExplicitCapacity(int minCapacity){ //如果空间不足 进行扩充 if(minCapacity - elementData.length > 0){ grow(minCapacity); } } //扩充容器 private void grow(int minCapacity){ int oldCapacity = elementData.length; //扩充1.5倍 原来的数加上原来的数右移一位 int newCapacity = oldCapacity + (oldCapacity>>1);//为什么用右移而不是除以2?因为右移比除以二快 if(newCapacity - minCapacity < 0){ newCapacity = minCapacity;//选出大的一方 } if(newCapacity - MAX_ARRAY_SIZE > 0){ newCapacity = hugeCapacity(minCapacity);//传入整型太大时候的处理 } //经过确定扩容的大小后直接创建 elementData = Arrays.copyOf(elementData, newCapacity); } //对创建时传入数字太大的情形做出处理 private static int hugeCapacity(int minCapacity){ if(minCapacity < 0){ throw new OutOfMemoryError(); } //如果1.5倍超出了MAX_ARRAY_SIZE则传入Integer.MAX_VALUE否则传入MAX_ARRAY_SIZE return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } public ArrayList(int initialSize){//带初始化容量大小的构造函数 super(); if(initialSize>0){//大于0直接创建 this.elementData = new Object[initialSize]; //原版jdk没有修改size 为什么不修改size? } else if(initialSize == 0){//等于0 直接赋空值 this.elementData = EMPTY_ELEMENTDATA; } else{//小于0直接抛出异常 throw new IllegalArgumentException("非法参数:"+initialSize); } } public ArrayList() throws Exception{ this(DEFAULT_CAPACITY);//调用有参构造函数 默认大小为10 } public ArrayList(Collection<? extends E> c){ elementData = c.toArray();//返回Object[] size = elementData.length; if(elementData.getClass() != Object[].class){//如果类型不同 则统一类型 elementData = Arrays.copyOf(elementData, size, Object[].class);//ArrayList的底层实现 数组 Arrays.copyOf() 赋值指定数组 } }@Override public boolean add(E e) { ensureCapacityInternal(size+1);//确保容器空间没问题 elementData[size++]=e; return true; }}
在阅读jdk中ArrayList的相关源码实现后的一些感悟:
1、jdk中对边界条件的处理(对边界情况的处理很全面,但是源代码中可生成ArrayList的尺寸的上限为Integer.MAX_VALUE,然而其实达到不了那么大,最大只能是:Integer.MAX_SIZE-8,因为这个ArrayList对应的底层数组本身需要8byte来进行储存)
2、每当ArrayList需要add,但是容量又不够的时候就需要扩容,扩容之后尺寸为扩容前尺寸的1.5倍,即原来尺寸加上原来尺寸右移一位,之所以使用右移一位而不是除以2是因为右移比除以2快
3、当ArrayList的所需要的尺寸特别大的时候,如果不是事先开辟好对应的空间,而是一次一次的添加,则会在添加的过程中一次又一次地遇到需要调用ensureCapacityInternal();的情况,效率很低。所以在使用ListArray的时候最好在初始化的时候传入恰当的尺寸,或者ListArray本身提供了ensureCapacity(int minCapacity)方法,可以一次创建对应的空间,从而很好地提高效率
4、ArrayList底层实际上是通过数组实现,开辟新空间的关键在于Arrays.copyOf(elementData,size),所以对ArrayList的查找和替换的时间复杂度为O(1),然而插入删除的需要涉及到后面大量元素的移动,时间复杂度为O(n)
5、ArrayList的contains()、indexOf()方法以及包含调用了这些方法的containsAll()、retainAll()、removeAll()方法等底层实际上都是使用了继承自Object对象的equals()方法,所以如果想要这些方法能够正常运行,需要保证存储在ArrayList里的数据类型的equals()方法经过了重写,比较的是对象之间的值而不是对象之间的内存地址。
- java中ArrayList的源码实现
- java中ArrayList的实现
- Java中ArrayList源码
- Java源码:ArrayList的实现原理
- ArrayList的源码实现
- Java ArrayList 内部源码实现
- Java中ArrayList源码解析
- 数据结构: Java中ArrayList的简单实现
- Java集合中ArrayList的实现原理
- Java 中 ArrayList 的实现解析
- Java中ArrayList的实现原理
- JAVA中ArrayList的底层基本实现
- java中ArrayList的实现模拟
- 深入Java集合源码学习系列:ArrayList的实现原理
- Java ArrayList的实现原理及源码解析
- java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析
- java ArrayList 的实现
- Java的ArrayList源码浅析
- CSS实现画出多种图形
- JDK8中ThreadLocal源码解析
- AngularJS自定义服务
- C++学习——泛型编程
- 树莓派Pi2安装ROS Kinetic Kame开发环境(基于Ubuntu 16.04LTS)
- java中ArrayList的源码实现
- 私人文章
- 二叉树线索化
- Android 代码混淆语法讲解及常用模板
- OpenCV学习笔记(一)——Linux下的OpenCV配置
- “实现模拟三次密码输入”的场景的c程序
- 剑指offer第19题(顺时针打印矩阵)
- SPOJREPEATS-Repeats
- 明确问题,加以解决。