相信对于使用过Java的人来说,ArrayList这个类大家一定不会陌生。

数据结构课上讲过,

Array是数组,它能根据下标直接找到相应的地址,所以索引速度很快,但是唯一的缺点是不能动态改变数组的长度,复杂度O(1)。

而List就是链表,它搜索相应地址都只能从链表头部一个一个找下去,直至找到对应的地址才停止,相比于数组来说,搜索速度肯定是慢的,但是有点是能动态的增删节点,复杂度O(n)。

而Java中这个ArrayList到底是什么东西呢?

先上代码,我们平时使用ArrayList一般这样使用:

public class ArrayListTest {

    public static void main( String[] args ) {
List<Integer> list = new ArrayList<Integer>();
list.add( );
list.add( );
list.get( );
list.remove( );
}
}

好,现在来解释每一步操作jdk做的事:

先看new ArrayList<>()初始化,

    public ArrayList(int initialCapacity) {
super();
if (initialCapacity < )
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
} /**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this();
}

很明显,如果初始化不指定capacity的话,默认初始化数组大小就是10。

其实细心发现,在重载的构造函数中,

this.elementData = new Object[initialCapacity];

这行代码暴露了ArrayList的本质,其实就是一个数组。

OK,现在我们拥有了一个长度为10的数组对象,现在我们执行add操作,看jdk操作

    public boolean add(E e) {
ensureCapacityInternal(size + ); // Increments modCount!!
elementData[size++] = e;
return true;
}

1.首先,暂且不理会ensureCapacityInternal()方法做的事,直接看【elementData[size++]=e】这行代码,显然地,是在elementData对象的size索引位置指向新元素,问题来了,万一size已经超出了当前数组的最大长度(假设是在第11个位置放置新元素),怎么办?

这里就要看ensureCapacityInternal方法了。

    private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

这里可以很清楚地看出,

minCapacity - elementData.length > 0

这行代码检查了新增的元素位置是否超出了当前数组对象的最大长度,基于上面的假设,此判断是成立的,所以需要继续往下看,看grow()方法。

    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);
}

看第二行代码,newCapacity = oldCapacity + oldCapacity / 2;
就是说每次当发现当前数组长度不足时,每次增加的步长是【0.5倍的当前长度】。
Ps.注意这里有一个坑,假如增加长度后超出了Max_ARRAY_SIZE(jdk定义为maxIntValue-8),直接返回MaxIntValue。 最后就是调用Arrays.copyOf方法了,里面主要调用的是System.arrayCopy方法,是一个JNI调用,有兴趣的同学可以去JDk官网看底层的实现,这里就不多累赘了。 --------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------

接着来看看remove方法。
    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; // Let gc do its work return oldValue;
}
remove就比较简单了,它的原理就是找到要删除的下标,假设数组[1,2,3,4,5]你要删除3,jdk的做法就是把[1,2]和[4,5]数组复制到原数组,形成新数组[1,2,4,5,5],
然后执行elementData[--Size]防止内存泄露,完毕~

总结:
ArrayList就是一个通过申请新内存来扩容的数组!

【Java集合类】ArrayList详解 (JDK7)的更多相关文章

  1. Java集合类的详解与应用

    Java集合类的详解与应用 集合简介: 1.定义:可以同时存储不同类型的数据 他的存储空间会随着数据的增大而增大 2.缺点:只能存储引用数据类型 3.优点:更加合理的利用空间,封装了更多的方法,用起来 ...

  2. java集合类,详解

    集合详解 1.1HashSet HashSet是Set接口的一个子类,主要的特点是:里面不能存放重复元素,而且采用散列的存储方法,所以没有顺序.这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致 ...

  3. Java.util.ArrayList详解

    java.util.ArrayList就是传说中的动态数组. 继承了关系,有此可看出ArrayList与list的collection的关系 public class ArrayList<E&g ...

  4. Java 8 ArrayList 详解

    GitHub Page: http://blog.cloudli.top/posts/Java-ArrayList/ ArrayList 继承于 AbstractList ,实现了 List.Rand ...

  5. java集合类图详解

  6. [转载]Java迭代器(iterator详解以及和for循环的区别)

    Java迭代器(iterator详解以及和for循环的区别) 觉得有用的话,欢迎一起讨论相互学习~[Follow] 转载自 https://blog.csdn.net/Jae_Wang/article ...

  7. ArrayList详解-源码分析

    ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ...

  8. 转:Java HashMap实现详解

    Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1.    HashMap概述:    HashMap是基于哈希表的M ...

  9. java集合框架详解

    java集合框架详解 一.Collection和Collections直接的区别 Collection是在java.util包下面的接口,是集合框架层次的父接口.常用的继承该接口的有list和set. ...

随机推荐

  1. Java经典案例之-判断质数(素数)

    /** * 描述:任意输入两个数n,m(n<m)判断n-m之间有多少个素数,并输出所有素数. * 分析:素数即质数,除1和本身之外,不能被其他自然数整除的数. * 判断素数的方法为:用一个数分别 ...

  2. Nodejs.sublime-build 在sublime3中的配置

    { "cmd": ["node", "$file"], "file_regex": "^[ ]*File \& ...

  3. HTML <head>

    HTML <head> 元素 <head> 元素包含了所有的头部标签元素.在 <head>元素中你可以插入脚本(scripts), 样式文件(CSS),及各种met ...

  4. python如何安装模块

    1.从 https://pypi.python.org/pypi/XXXX  下载压缩包 2.解压所下载的压缩包 3.CD到解压目录,执行 sudo python setup.py install

  5. 走进React

    走进React React是一个构建用户界面的JavaScript库,是Facebook公司在2013年5月在github上开源的.其特点如下: 高效--React通过对DOM的模拟,最大程度地减少和 ...

  6. iOS 多线程NSThread理解与场景示例

    NSThread是相对GCD和NSOperationQuene而言,比较轻量级的一种多线程处理方式. 但同时,它的弊端就是需要自己管理线程的生命周期,以及线程同步:而另外两种不需要自己管理. 常见方法 ...

  7. 【蒙地卡罗法求PI】

    /* 蒙地卡罗法求PI 说明 蒙地卡罗为摩洛哥王国之首都,该国位于法国与义大利国境,以赌博闻名.蒙地卡罗的基本原理为以乱数配合面积公式来进行解题,这种以机 率来解题的方式带有赌博的意味,虽然在精确度上 ...

  8. 在Oracle中数据库、表空间、表之间的关系

    在oracle中,表空间是存储概念上的,建立表空间需要有对应的数据文件,数据文件建立好之后直接会把一定的磁盘空间分配给它,这样可以对数据库的存储空间进行有效的管理.然后在建表的时候指定对应的表空间,该 ...

  9. Xcode7 beta 网络请求报错:The resource could not be loaded because the App Transport

    Xcode7 beta 网络请求报错:The resource could not be loaded because the App Transport Xcode7 beta 网络请求报错:The ...

  10. LinQ 创建连接、简单增删改查

    LINQ--语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同的方式操 ...