ArrayList源码阅读

ArrayList实现

继承关系

java.lang.Object

- java.util.AbstractCollection<E>

- java.util.AbstractList<E>

- java.util.ArrayList<E>

实现接口

Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess

关键属性

private transient Object[] elementData;    //transient修饰不会序列化,但实现了Serializable接口,重写了readObject和writeObject方法只序列化实际大小

private int size;    //实际大小

常见方法

public boolean add(E e) {
	ensureCapacity(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}
 public void add(int index, E element) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
	ensureCapacity(size+1);  // Increments modCount!!
	System.arraycopy(elementData, index, elementData, index + 1,
			 size - index); //elementData[index,size) --> elementData[index+1,size+1)
	elementData[index] = element;
	size++;
 }

ensureCapacity扩容方法:开始前有对modCount修改操作,实现fast-fail迭代

public void ensureCapacity(int minCapacity) {
        modCount++;
        int oldCapacity = elementData.length;
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            int newCapacity = (oldCapacity * 3)/2 + 1; //0.5倍扩容策略
                if (newCapacity < minCapacity)
            newCapacity = minCapacity;
                // minCapacity is usually close to size, so this is a win:
                elementData = Arrays.copyOf(elementData, newCapacity);
        }
}

remove方法,移动index+1及其后面元素,并将最后一个元素设置为null,帮助GC回收

 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[index+1,size) -->elementData[index,size-1)
	elementData[--size] = null; // Let gc do its work
	return oldValue;
 }
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;
}

fastRemove是私有方法没有返回old value

private void fastRemove(int index) {
        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
}

重写readObject和writeObject进行序列化和反序列化,保证只会序列化实际大小的数组避免空间浪费,可以看到writeObject的时候有fast fail判断

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
	// Read in size, and any hidden stuff
	s.defaultReadObject();
        // Read in array length and allocate array
        int arrayLength = s.readInt();
        Object[] a = elementData = new Object[arrayLength];
	// Read in all elements in the proper order.
	for (int i=0; i<size; i++)
            a[i] = s.readObject();
}
 private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
	// Write out element count, and any hidden stuff
	int expectedModCount = modCount;
	s.defaultWriteObject();
        // Write out array length
        s.writeInt(elementData.length);
	// Write out all elements in the proper order.
	for (int i=0; i<size; i++)
            s.writeObject(elementData[i]);
	if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
}

迭代器实现

ArrayList支持两种迭代器:IteratorListIterator(双向迭代),实现在AbstractList中

Iterator通过内部类AbstractList$Itr实现

Itr类定义

private class Itr implements Iterator<E>

属性包括

int cursor = 0;   //当前遍历的下标

int lastRet = -1; //最近调用next或previous返回的下标,当调用自身remove方法删除元素后,重置为-1

int expectedModCount = modCount;  //用于检测遍历过程中并发修改

重要方法

hasnext和next方法

public boolean hasNext() {
       return cursor != size();
}
public E next() {
       checkForComodification();
       try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	 } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	}
}

remove方法

public void remove() {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();
	    try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	    }
}

-next和remove方法前都需要调用checkForComodification检验容器是否被修改,若被修改则抛出ConcurrentModificationException

-调用迭代器自身remove方法不会引起ConcurrentModificationException,这是因为删除元素以后,expectedModCount被重新设置了(expectedModCount
= modCount)

-可以看到remove方法执行完一次删除以后,将lastRet设置为-1,下次接着调用就会抛异常。

ListIterator通过内部类ListItr来实现,其继承了单向迭代器Itr并实现双向迭代器接口ListIterator

ListItr类定义

private class ListItr extends Itr implements ListIterator<E>

支持指定cursor位置构造

ListItr(int index) {
      cursor = index;
}

previous和next方法设置lastRet不同,next方法是cursor未加1之前的值,而previous是cursor减1以后的值

public boolean hasPrevious() {
	    return cursor != 0;
	}
	public E previous() {
		checkForComodification();
        try {
                int i = cursor - 1;
                E previous = get(i);
                lastRet = cursor = i;
                return previous;
        } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
        }
}

set方法是在lastRet处修改该元素的值,向前遍历一次previous则为cursor-1,向后遍历一次则为cursor

public void set(E e) {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();
	    try {
		AbstractList.this.set(lastRet, e);
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException ex) {
		throw new ConcurrentModificationException();
	    }
}

add方法在当前cursor位置添加,并将cusor加1

public void add(E e) {
        checkForComodification();
	try {
	    	AbstractList.this.add(cursor++, e);
	    	lastRet = -1;
	    	expectedModCount = modCount;
	} catch (IndexOutOfBoundsException ex) {
	    	throw new ConcurrentModificationException();
	}
}

总结

1. ArrayList内部通过数组方式实现,采用加倍策略而非指定常量扩容,指定位置添加采用平摊分析复杂度为O(1)

2. ArrayList中数组声明为transient不会序列化,重写了readObject和writeObject进行反序列化和序列化,保证只序列化有效大小的数组元素。

3. 迭代器支持fast-fail,当迭代过程中检测到容器结构发生变化添加或删除元素时,会抛出ConcurrentModificationException,通过内部modCount实现。调用迭代器自身remove方法和双向迭代器中add和set方法不会引起并发修改异常。

4. 迭代器中remove和set方法需要调用next或previous内部lastRet成员设置为有效索引才可以,并且调用完remove方法以后lastRet又重新设置为-1,不能直接反复调用。

参考

OpenJDK 源代码阅读之
ArrayList

时间: 2024-08-02 20:33:56

ArrayList源码阅读的相关文章

java8 ArrayList源码阅读

转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vector,LinkedList http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/ArrayList.java 实现原理 transient Object[] elementData; // 存放元素

ArrayList源码阅读分析(JDK1.8)

 ArrayList也是我们开发过程中常用的集合之一,虽然实现原理比较简单,但是还是通过本文简单的介绍和分析下,底层是用Object数组实现的,下面直接进入正题. 一.  ArrayLis的默认构造函数说明           从上面的代码可以看出,当新建一个  ArrayList集合的时候,如果不指定容量,就是创建了一个容量为10,数组为空数组的List集合,插入一个元素的时候会将空数组初始化为长度为容量的数组. 二.  ArrayLis的add()函数源码分析 二.  ArrayLis的re

ArrayList源码阅读笔记(基于JDk1.8)

关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Object[] EMPTY_ELEMENTDATA = {}; 如果elementData用这个变量初始化,则DEFAULT_CAPACITY不会参与数组大小的运算 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

Java 1.8 ArrayList源码解析

1 // 非线程安全 2 // 继承了AbstractList类 3 // 实现了List.RandomAccess.Cloneable.java.io.Serializable接口 4 // 后面3个接口是标记接口,没有抽象方法. 5 // 表示ArrayList可以随机访问.浅复制.序列化和反序列化. 6 public class ArrayList<E> extends AbstractList<E> 7 implements List<E>, RandomAcc

OpenJDK 源码阅读之 ArrayList

概要 类继承关系 java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java.util.ArrayList<E> 定义 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serial

jdk源码阅读笔记之java集合框架(二)(ArrayList)

关于ArrayList的分析,会从且仅从其添加(add)与删除(remove)方法入手. ArrayList类定义: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Monaco } span.s1 { color: #931a68 } public class ArrayList<E> extends AbstractList<E> implements List<E> ArrayList基本属性: /** *

【源码阅读】Java集合 - ArrayList深度源码解读

Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. [email protected] JDK版本 JDK 1.8.0_110 概述总结 ArrayList底层是通过数组实现的:其中capacity表示底层数组的长度,而ArrayList长度由size表示: ArrayList允许存放null元素,也可以查找null所在的index, 比如indexOf(), lastIndex

JDK部分源码阅读与理解

本文为博主原创,允许转载,但请声明原文地址:http://www.coselding.cn/article/2016/05/31/JDK部分源码阅读与理解/ 不喜欢重复造轮子,不喜欢贴各种东西.JDK代码什么的,让整篇文章很乱...JDK源码谁都有,没什么好贴的...如果你没看过JDK源码,建议打开Eclipse边看源码边看这篇文章,看过的可以把这篇文章当成是知识点备忘录... JDK容器类中有大量的空指针.数组越界.状态异常等异常处理,这些不是重点,我们关注的应该是它的一些底层的具体实现,这篇

如何阅读Java源码 阅读java的真实体会

刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧,如果你从来没有学过Java,或是任何一门编程语言如C++,一开始去啃<Core Java>,你是很难从中吸收到营养的,特别是<深入Java虚拟机>这类书,别人觉得好,未必适合现在的你. 虽然Tomcat的源码很漂亮,但我绝不建议你一开始就读它.我文中会专门谈到这个,暂时不展开. 强烈