Java集合框架ArrayList源码分析(一)_java

ArrayList底层维护的是一个动态数组,每个ArrayList实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。

 ArrayList不是同步的(也就是说不是线程安全的),如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步,在多线程环境下,可以使用Collections.synchronizedList方法声明一个线程安全的ArrayList,例如:
List arraylist = Collections.synchronizedList(new ArrayList());
下面通过ArrayList的源码来分析其原理。
1、ArrayList的构造方法:ArrayList提供了三种不同的构造方法
1) ArrayList(),构造一个初始容量为 10 的空列表。
2) ArrayList(int initialCapacity),构造一个具有指定初始容量的空列表。
3) ArrayList(Collection<? extends E> c),构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。

源码如下: 

private transient Object[] elementData;

public ArrayList(int initialCapacity) {

  super();

  if (initialCapacity < 0)

    throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);

  this.elementData = new Object[initialCapacity]; //生成一个长度为10的Object类型的数组

 }

 public ArrayList() {

  this(10); //调用ArrayList(int i)

 }<br><br>

 public ArrayList(Collection<? extends E> c) {

    elementData = c.toArray();  //返回包含此 collection 中所有元素的数组

  size = elementData.length;

  // c.toArray might (incorrectly) not return Object[] (see 6260652)

  if (elementData.getClass() != Object[].class)

   elementData = Arrays.copyOf(elementData, size, Object[].class); //复制指定的数组,返回包含相同元素和长度的Object类型的数组

 }

当采用不带参数的构造方法ArrayList()生成一个集合对象时,其实是在底层调用ArrayList(int initialCapacity)这一构造方法生产一个长度为10的Object类型的数组。当采用带有集合类型参数的构造方法时,在底层生成一个包含相同的元素和长度的Object类型的数组。 

2、add方法:ArrayList提供了两种添加元素的add方法
1) add(E e),将指定的元素添加到此列表的尾部。
2) add(int index, E e),将指定的元素插入此列表中的指定位置。向右移动当前位于该位置的元素(如果有)以及所有后续元素(将其索引加 1)private int size;

public boolean add(E e) {

  ensureCapacity(size + 1); // 扩大数组容量

  elementData[size++] = e;  //将元素e添加到下标为size的Object数组中,并且执行size++

  return true;

  }

 public void add(int index, E element) {

  if (index > size || index < 0) //如果指定要插入的数组下标超过数组容量或者指定的下标小于0,抛异常

    throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);

  ensureCapacity(size+1); // 扩大数组容量

  System.arraycopy(elementData, index, elementData, index + 1,size - index); //从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。<br>                                          // elementData --- 源数组  index --- 源数组中的起始位置  <br>                                          // elementData --- 目标数组 index+1 --- 目标数组中的起始位置<br>                                          // size - index --- 要复制的数组元素的数量

  elementData[index] = element; //将要添加的元素放到指定的数组下标处

  size++;

  }
public void ensureCapacity(int minCapacity) {

  modCount++;

  int oldCapacity = elementData.length; //原数组的容量

  if (minCapacity > oldCapacity) {

    Object oldData[] = elementData;

    int newCapacity = (oldCapacity * 3)/2 + 1; //定义新数组的容量,为原数组容量的1.5倍+1

      if (newCapacity < minCapacity)

    newCapacity = minCapacity;

      // minCapacity is usually close to size, so this is a win:

      elementData = Arrays.copyOf(elementData, newCapacity); //复制指定的数组,返回新数组的容量为newCapacity

  }

  }

如果集合中添加的元素超过了10个,那么ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1,并将原数组中的元素copy到新数组中,并且后续添加的元素都会放在新数组中,当新数组的长度无法容纳新添加的元素时,重复该过程。这就是集合添加元素的实现原理。

3、get方法:
 1) get(int index),返回此列表中指定位置上的元素。

public E get(int index) {
  RangeCheck(index); //检查传入的指定下标是否合法

  return (E) elementData[index]; //返回数组下标为index的数组元素

  }
private void RangeCheck(int index) {
  if (index >= size) //如果传入的下标大于或等于集合的容量,抛异常
    throw new IndexOutOfBoundsException(
    "Index: "+index+", Size: "+size);

  }

4、remove方法:
1) E remove(int index),移除此列表中指定位置上的元素。向左移动所有后续元素(将其索引减 1)。
2) boolean remove(Object o),移除此列表中首次出现的指定元素(如果存在)。如果列表不包含此元素,则列表不做改动,返回boolean值。 

public E remove(int index) {

  RangeCheck(index); //检查指定的下标是否合法

  modCount++;

  E oldValue = (E) 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;

  }

 public boolean remove(Object o) {

  if (o == null) { //如果传入的参数为null

      for (int index = 0; index < size; index++)

    if (elementData[index] == null) { //移除首次出现的null

      fastRemove(index);

      return true;

    }

  } else {

    for (int index = 0; index < size; index++)

    if (o.equals(elementData[index])) {

      fastRemove(index);

      return true;

    }

    }

  return false;

  }

private void fastRemove(int index) { //移除指定位置的元素,实现方法类似remove(int i)

    modCount++;

    int numMoved = size - index - 1;

    if (numMoved > 0)

      System.arraycopy(elementData, index+1, elementData, index,

               numMoved);

    elementData[--size] = null; // Let gc do its work

  }

5、clone方法:
1) Object clone(),返回此ArrayList实例的浅表副本(不复制这些元素本身) 。

public Object clone() {
  try {
    ArrayList<E> v = (ArrayList<E>) super.clone(); //调用Object类的clone方法返回一个ArrayList对象
    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();

  }

  }

以上通过对ArrayList部分关键源码的分析,知道了ArrayList底层的实现原理,关于ArrayList源码有以下几点几点总结:
 1) ArrayList 底层是基于数组来实现的,可以通过下标准确的找到目标元素,因此查找的效率高;但是添加或删除元素会涉及到大量元素的位置移动,效率低。
 2) ArrayList提供了三种不同的构造方法,无参数的构造方法默认在底层生成一个长度为10的Object类型的数组,当集合中添加的元素个数大于10,数组会自动进行扩容,即生成一个新的数组,并将原数组的元素放到新数组中。
3) ensureCapacity方法对数组进行扩容,它会生成一个新数组,长度是原数组的1.5倍+1,随着向ArrayList中不断添加元素,当数组长度无法满足需要时,重复该过程。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, arraylist
集合框架
java集合框架源码剖析、java集合框架源码、java arraylist 源码、java集合arraylist、java集合框架,以便于您获取更多的相关知识。

时间: 2024-08-30 09:04:19

Java集合框架ArrayList源码分析(一)_java的相关文章

ArrayList源码分析(jdk1.8)

前几天自我学习了ArrayList的源码,写了篇云笔记,现将其发布到博客,供大家学习交流,本人并非大神,如有任何问题,欢迎批评指正. 最初是看了这篇文章http://www.cnblogs.com/hzmark/archive/2012/12/20/ArrayList.html,不过是基于jdk1.6的,遂自己分析源码并写下此文,在此表示感谢.转载请注明出处,谢谢,http://blog.csdn.net/u010887744/article/details/49496093. ArrayLis

Java StringBuilder和StringBuffer源码分析_java

StringBuilder与StringBuffer是两个常用的操作字符串的类.大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的.前者是JDK1.5加入的,后者在JDK1.0就有了.下面分析一下它们的内部实现. 一.继承关系 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence public

Linux驱动修炼之道-RTC子系统框架与源码分析【转】

转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://blog.csdn.net/woshixingaaa/archive/2011/05/21/6436215.aspx RTC(实时时钟)是一种典型的字符设备,作为一种字符设备驱动,RTC需要有file_operations中接口函数的实现,如open(),release(),read(),poll(),

求一份Java SpringMVC框架的源码!

问题描述 为了节约时间,那位仁兄若有SpringMVC项目的框架,发一份给我!O(∩_∩)O谢谢QQ:1669852599邮箱地址:1669852599@qq.com 解决方案 解决方案二:网上找去,有N多版本.解决方案三:就是想找一个相对稳定点的!然后自己改动~~便于后期的维护!O(∩_∩)O谢谢解决方案四:jeecms就是springmvc写的,开源

Java集合框架:HashMap

Java集合框架概述   Java集合框架无论是在工作.学习.面试中都会经常涉及到,相信各位也并不陌生,其强大也不用多说,博主最近翻阅java集合框架的源码以及搜索一些相关资料整理出Java集合框架的系列.一方面是做一个总结,方便以后查阅,另一方面希望各位小伙伴能够提出不足之处,我会及时更新修改.   博主从网上抠了一张图,觉得画得还是比较形象的,给大家参考一下.   上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如Abst

java集合框架03——ArrayList和源码分析

   上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习.首先学习List.而ArrayList又是List中最为常用的,因此本章先学习ArrayList.先对ArrayList有个整体的认识,然后学习它的源码,深入剖析ArrayList. 1. ArrayList简介     首先看看ArrayList与Collection的关系:     ArrayList的继承关系如下: [java] view plain copy  

Java集合框架详解

这篇文章详细对比以及分析了Java的集合框架的原理使用以及比较. ArrayList ArrayList就是传说中的动态数组,就是Array的复杂版本,它提供了如下一些好处:动态的增加和减少元素.灵活的设置数组的大小-- ArrayList底层是数组,并且add remove指定位置元素的时候,是通过memcpy来实现的.我们直接来看源码: ArrayList源码分析: 123456789101112131415161718192021222324252627282930313233343536

java集合框架10——TreeMap和源码分析(一)

版权声明:尊重博主原创文章,转载请注明出处哦~http://blog.csdn.net/eson_15/article/details/51217741 目录(?)[+] 前面讨论完了HashMap和HashTable的源码,这一节我们来讨论一下TreeMap.先从整体上把握TreeMap,然后分析其源码,深入剖析TreeMap的实现. 1. TreeMap简介         TreeMap是一个有序的key-value集合,它内部是通过红-黑树实现的,如果对红-黑树不太了解,请先参考下这篇博

java集合框架04——LinkedList和源码分析

 上一章学习了ArrayList,并分析了其源码,这一章我们将对LinkedList的具体实现进行详细的学习.依然遵循上一章的步骤,先对LinkedList有个整体的认识,然后学习它的源码,深入剖析LinkedList. LinkedList简介     首先看看LinkedList与Collection的关系:                                                       LinkedList的继承关系如下: [java] view plain c