1. 扩容

ArrayList扩容包括ensureCapacity(对外开放)和ensureCapacityInternal(内部隐式调用)两个接口:

1' 两者都调用ensureExplicitCapacity接口进行扩容

2' ensureExplicitCapacity在当前容量 < 指定的最小容量时,进行扩容

3' 扩容策略:新容量 = 旧容量 * 1.5

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final int DEFAULT_CAPACITY = 10; // 默认初始容量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认容量空数组:默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {}; // 空数组:指定容量为0
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 最大数组大小 transient Object[] elementData;
private int size; public ArrayList() { // 未指定初始容量
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // 分配默认容量空数组
} public ArrayList(int initialCapacity) { // 指定初始容量
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity]; // 为elementData分配空间
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA; // 分配空数组
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
} public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class); // 拷贝elementData
} else {
this.elementData = EMPTY_ELEMENTDATA; // 分配空数组
}
} public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
if (minCapacity > minExpand) { // 若elementData为默认容量空数组,则指定最小容量必须大于默认容量(10)才真正进一步扩容
ensureExplicitCapacity(minCapacity);
}
} public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
} private void ensureCapacityInternal(int minCapacity) {
// elementData为默认容量空数组,则在指定的最小容量和默认容量(10)中选择较大大者进行扩容
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0) // 若指定的最小容量 > 当前容量,则按指定的最小容量扩容
grow(minCapacity);
} private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量 = 旧容量 * 1.5
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();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
} ... ...
}
public class Arrays {
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
} public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] // Object[]类型
: (T[]) Array.newInstance(newType.getComponentType(), newLength); // 其它数组类型
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
} ... ...
}

2. 迭代器

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
... ...
public Iterator<E> iterator() {
return new Itr();
} public ListIterator<E> listIterator() {
return new ListItr(0);
} public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
} ... ...
}

1)ArrayList.Itr

private class Itr implements Iterator<E> {
int cursor; // 下次返回元素的位置
int lastRet = -1; // 当前返回元素的位置
int expectedModCount = modCount; // ArrayList.this.modCount
// 判断在迭代过程中是否调用过ArrayList方法修改过elementData
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
} public boolean hasNext() {
return cursor != size;
} public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1; // cursor++
return (E) elementData[lastRet = i]; // lastRet纪录当前返回元素的位置,cursor = lastRet + 1
} public void remove() {
if (lastRet < 0) // 未调用过Itr.next || 未调用ListItr.previous || 已调用过Itr.remove || 已调用过ListItr.add
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet); // 删除lastRet处的元素
cursor = lastRet; // 不影响下次previous或next的调用
lastRet = -1;
expectedModCount = modCount; // ArrayList.remove方法将使modCount++
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} ... ...
}

2)ArrayList.ListItr

private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
} public boolean hasPrevious() {
return cursor != 0;
} public int nextIndex() { // 下次调用next方法返回元素的位置
return cursor;
} public int previousIndex() { // 下次调用previous方法返回元素的位置
return cursor - 1;
} public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i]; // lastRet纪录当前返回元素的位置,cursor = lastRet
} public void set(E e) {
if (lastRet < 0) // 未调用Itr.next || 未调用ListItr.previous || 已调用Itr.remove || 已调用ListItr.add
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e); // 设置lastRet处的元素
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e); // 在cursor处添加新元素等价于:
// 1. 在用previous方法返回元素时:在lastRet前置位插入元素
// 2. 在用next方法返回元素时:在lastRet后置位插入元素

cursor = i + 1; // 下次调用previous方法则返回刚插入的元素,不影响下次next方法的调用
lastRet = -1;
expectedModCount = modCount; // ArrayList.add方法将使modCount++
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}

ArrayList之扩容与迭代器的更多相关文章

  1. Arraylist动态扩容详解

    ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长. ArrayList不是线程安全的,只能用在单线程环境下. 实现了Serializable接口,因此它支 ...

  2. 设计模式(8) - 迭代器模式(iterator)- 实现ArrayList和linkedList的迭代器

    上周六就開始写这篇博客,之后一直耽误了.到前天才開始写.今天醒的早,就把这部分整理一下. 本文内容參考易学设计模式和马士兵的迭代器模式的视频. 了解迭代器模式一个作用就是让你在使用 迭代器遍历集合类的 ...

  3. ArrayList增加扩容问题 源码分析

    public class ArrayList<E>{ private static final int DEFAULT_CAPACITY = 10;//默认的容量是10 private s ...

  4. ArrayList的扩容机制

    一.ArrayList的扩容机制 1.扩容的计算方式是向右位移,即:newSize = this.size + (this.size>>1).向右位移,只有在当前值为偶数时,才是除以2:奇 ...

  5. 【数组】- ArrayList自动扩容机制

    不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力, ...

  6. 简单复习一下ArrayList的扩容原理

    刚刚跟几个好朋友喝完小酒回家,简单大概复习一下ArrayList的扩容原理,由于头有点小晕,就只大概说一下扩容的原理哈: 首先ArrayList实现了List接口,继承了AbstractList,大家 ...

  7. ArrayList动态扩容机制

    初始化:有三种方式 1.默认的构造器,将会以默认的大小来初始化内部的数组:public ArrayList(); 2.用一个ICollection对象来构造,并将该集合的元素添加到ArrayList: ...

  8. 关于ArrayList的扩容机制

    关于ArrayList的扩容机制 ArrayList作为List接口常用的一个实现类,其底层数据接口由数组实现,可以保证O(1) 复杂度的随机查找, 在增删效率上不如LinkedList,但是在查询效 ...

  9. Java ArrayList自动扩容机制

    动态扩容 1.add(E e)方法中 ①  ensureCapacityInternal(size+1),确保内部容量,size是添加前数组内元素的数量 ②  elementData[size++] ...

随机推荐

  1. windows 上启动appium

    import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandl ...

  2. [Leetcode Week13]Palindrome Partitioning

    Palindrome Partitioning 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/palindrome-partitioning/desc ...

  3. Bzoj-2301 [HAOI2011]Problem b 容斥原理,Mobius反演,分块

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2301 题意:多次询问,求有多少对数满足 gcd(x,y)=k, a<=x<=b ...

  4. 【总结】IE和Firefox的Javascript兼容性总结

    长久以来JavaScript兼容性一直是Web开发者的一个主要问题.在正式规范.事实标准以及各种实现之间的存在的差异让许多开发者日夜煎熬.为此,主要从以下几方面差异总结IE和Firefox的Javas ...

  5. JS实现判断滚动条滚到页面底部并执行事件的方法

    需要了解三个dom元素,分别是:clientHeight.offsetHeight.scrollTop. clientHeight:这个元素的高度,占用整个空间的高度,所以,如果一个div有滚动条,那 ...

  6. 【C++】C++11的auto和decltype关键字

    转自: http://www.linuxidc.com/Linux/2015-02/113568.htm 今天要介绍C++11中两个重要的关键字,即auto和decltype.实际上在C++98中,已 ...

  7. socket编程之select(),poll(),epoll()

    socket编程,通信 client端  socket() ----->connect() ------->recv() -----> close(); server端 socket ...

  8. taskeng.exe禁用

    打开控制面板. 打开管理工具. 打开任务计划程序. 双击左边的的任务计划程序库,看到MySQL,然后双击MysQL,接着看到Installer,再双击Installer,这时候想禁止可以直接禁止 右击 ...

  9. 四十八 常用内建模块 HTMLParser

    如果我们要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看里面的内容到底是新闻.图片还是视频. 假设第一步已经完成了,第二步应该如何解析HTML呢? HTML ...

  10. php jsonp跨域访问

    项目中有个上传图片需要实时预览的,但又是两个系统的访问,故想了一下解决方案: 在新系统中上传图片后处理设置session,旧系统跨域访问获取对应session,进行对应模板预览. 上传图片预览按钮对应 ...