`
javandroid
  • 浏览: 25601 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

ArrayList源码分析

 
阅读更多

版本说明:jdk1.7.0_79

ArrayList


属性

//默认的初始容量大小,为10
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};

//用来存放元素的数组。
private transient Object[] elementData;

//存放的元素个数
private int size;


构造方法

public ArrayList(int initialCapacity)
public ArrayList()
public ArrayList(Collection<? extends E> c)

创建ArrayList时,可以指定初始容量值。如果没有指定初始容量,则使用默认的容量值DEFAULT_CAPACITY=10。

也可以用其它容器填充的方式来创建ArrayList,其容量值就其它容器的size值(存放元素的个数)。【刚好装满】

但是初始容量既不能设置过大,也不能过小。如果过大,但元素增长过慢,则导致内存浪费。如果过小,造成频繁的扩容(内部元素移动),影响效率。

参考博客:关于ArrayList的初始容量以及扩容的效率问题

add方法

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

该方法是将元素添加到列表尾部

get方法

    public E get(int index) {
        //先检查index是否越界
        rangeCheck(index);
 
        return elementData(index);
    }

remove方法

删除指定index处的元素

  public E remove(int index) {
    //检查index是否越界
            rangeCheck(index);
   
    modCount++;
            //暂存要删除的元素
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
            //如果删除位置不是末尾,进行元素的移动
    if (numMoved > 0)
      System.arraycopy(elementData, index+1, elementData, index, numMoved);//index之后的所有元素都往前挪动。
    
            //将末位置设为null。size值减1
            elementData[--size] = null; // 【clear to let GC do its work】

            //返回删除的元素
    return oldValue;
  }
如果删除的是末尾的元素,直接删除即可。如果是其它位置,则需要将删除位后面的所有元素往前移动。

elementData[--size] = null这段代码有两层意思。
1.删除元素后,末位元素已经没有存在的意义了,所以将其设为null。
2.如果该元素是某个对象的引用,且不存在其它对该对象的引用,则设为null之后,该对象就成为了垃圾,垃圾回收机制开始工作(不保证进行回收)
注意:如果是复杂类型,容器中存放的是对象的引用,所以删除时仅仅删除的是引用,真实的对象并未删除。


remove(Object o)

删除第一个出现在ArrayList中的元素

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

ArrayList自动扩容机制

我们知道ArrayList优于数组之处在于它具有自动扩容机制,也就是当ArrayList中存放的元素个数达到了其容量之后,继续向其中添加元素,它会帮我们自动扩充容量。ArrayList在添加元素时先会确保内部容量可用,会调用ensureCapacityInternal(size + 1);
查看源码可知,有两个确保容量的方法。
  • public void ensureCapacity(int minCapacity)
  • private void ensureCapacityInternal(int minCapacity)
公有的扩容方法说明,我们可以手动的对ArrayList进行扩容。
私有的那个方法名后面有个internal(内部的),说明该方法仅供ArrayList内部使用。我们重点关注这个私有的扩容方法。
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);//***
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//***
    }
    private void grow(int minCapacity) {
  // overflow-conscious code
  int oldCapacity = elementData.length;
  int newCapacity = oldCapacity + (oldCapacity >> 1);//>>表示右移一位,相当于除以2
  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:
  lementData = Arrays.copyOf(elementData, newCapacity);
  }

int newCapacity = oldCapacity + (oldCapacity >> 1),从而可以知道ArrayList扩容到原容量的1.5倍(约等于)
而在JDK6中扩容实现如下
int newCapacity = (oldCapacity * 3)/2 + 1;
也就是说,如果初始容量为10,JDK7扩容至15,而JDK6扩容至16,但大约都是原来的1.5倍。
为什么jdk7会换了个写法,其实原因很简单。oldCapacity直接乘以3(暴增),很可能会造成int溢出,而jdk6中的写法则是缓慢的增加,相比要安全的多。

更多关于ArrayList和Vector扩容1.5倍的讨论请参阅:

Why does ensureCapacity() in Java ArrayList extend the capacity with a const 1.5 or (oldCapacity * 3)/2 + 1?

Logic used in ensureCapacity method in ArrayList


快速失败机制


总结

ArrayList底层使用数组实现。随机访问速度快,插入和移除操作速度慢。
ArrayList具有自动扩容机制。
ArrayList是非线程安全的。

ArrayList和Vector的比较请看Vector和ArrayList的比较
分享到:
评论

相关推荐

    ArrayList源码分析(含jdk1.8).pdf

    在了解ArrayList的源码分析时,我们主要探讨其在Java Development Kit (JDK) 1.8中的实现。ArrayList是一个非常重要的集合框架,用于动态数组的实现,其功能类似于数组,但可以在运行时动态调整大小。它是一个非线程...

    硬核ArrayList源码分析,答应我每天看一遍好么

    《硬核ArrayList源码分析——深入理解Java集合框架》 ArrayList是Java集合框架中的一个重要组成部分,它是基于动态数组实现的列表。在Java 1.8版本中,ArrayList的实现细节和内部工作原理对于理解其性能和行为至关...

    ArrayList源码分析.docx 等

    转换为其内部数组 `elementData`,然后根据转换后的数组长度设置 `size`。这里需要注意的是,如果 `c.toArray()` ...在面试中,深入理解 ArrayList 的源码和其与其他数据结构的区别是展示 Java 基础技能的重要方面。

    ArrayList源码分析_016.pdf

    ArrayList是Java集合框架中的一种重要实现,它是List接口的一个具体类,提供了动态数组的功能。ArrayList在内部使用一个Object类型的数组来存储元素,因此它支持快速的随机访问,这是由其实现了RandomAccess接口所...

    Java编程中ArrayList源码分析

    Java编程中ArrayList源码分析 Java编程中ArrayList源码分析是Java编程中一个重要的知识点,对于Java开发者来说,了解ArrayList的源码可以帮助他们更好地理解Java集合框架的实现机制,从而提高自己的编程水平。 ...

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

    《深入剖析Java集合框架ArrayList源码》 Java集合框架中的ArrayList是开发者常用的数据结构,它是一种基于动态数组实现的列表。ArrayList的特点在于它的内部结构、性能优化以及在并发环境下的处理方式。本文将深入...

    ArrayList 源码深度解析

    ArrayList 源码深度解析 一、重新认识ArrayList 什么是ArrayList? ArrayList是基于数组实现的List类,封装了一个动态再分配的Object数组,以达到可以动态增长和缩减的索引序列。 长啥样? 如图,是一个长度为6,...

    ArrayList源码.zip

    源码分析中,我们还可以看到ArrayList是如何实现迭代器(Iterator)的。迭代器是Java集合框架的重要组成部分,允许我们遍历ArrayList的元素而不需要暴露底层的实现细节。ArrayList的迭代器实现了hasNext()和next()...

    Java集合系列之ArrayList源码分析

    本文将深入ArrayList的源码,探讨其内部实现、构造方法以及增删改查操作。 1. **内部结构与构造方法** ArrayList的核心成员变量是一个Object类型的数组`elementData`,用于存储元素。数组的初始容量默认为10,可以...

    【死磕Java集合】-集合源码分析.pdf

    二、ArrayList源码分析 ArrayList是一种基于数组实现的List,提供了快速的随机访问和插入删除元素的能力。ArrayList的继承体系中,它继承了AbstractList,实现了List接口。 ArrayList的主要属性包括元素数组...

    java提高篇(二一)-----ArrayList.pdf

    ArrayList 源码分析: ArrayList 底层采用数组实现,所以它的操作基本上都是基于对数组的操作。ArrayList 提供了三个构造函数: 1. ArrayList():默认构造函数,提供初始容量为 10 的空列表。 2. ArrayList(int ...

    ArrayList源码和多线程安全问题分析

    ArrayList源码和多线程安全问题分析 在 Java 编程语言中,ArrayList 是一个常用的集合类,它提供了动态数组的实现,能够存储大量的数据。但是,在多线程环境下,ArrayList 并不是线程安全的。这篇文章主要介绍了 ...

    第二章 ArrayList源码解析1

    第二章 ArrayList源码解析 ArrayList是Java集合框架中的一种动态数组,它继承自AbstractList,并实现了List接口。ArrayList主要用于存储可变大小的对象列表,它的核心是通过一个Object类型的数组elementData来实现...

    ArrayList.md

    史上最全ArrayList源码分析

    ArrayList的源码

    源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556

Global site tag (gtag.js) - Google Analytics