一、ArrayList源码分析

1、全局变量

(1)默认容量(主要是通过无参构造函数创建ArrayList时第一次add执行扩容操作时指定的elementData的数组容量为10)

 private static final int DEFAULT_CAPACITY = 10;

(2)空的对象数组(当通过指定容量的构造方法创建ArrayList时指定给elementData,用于区分DEFAULTCAPACITY_EMPTY_ELEMENTDATA,比如说在得到最小扩容容量时判断elementData是通过哪个构造函数指定的哪个数组)

 private static final Object[] EMPTY_ELEMENTDATA = {};

(3)默认的空数组(用于区分EMPTY_ELEMENTDATA,主要针对构造函数)

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

(4)存放数据的数组的缓存变量,不可序列化

 transient Object[] elementData;

(5)元素数量(注意区分length,length是数组elementData的容量,而size是元素数量)

 private int size;

2、构造函数

(1)带有容量initialCapacity的构造方法

 public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

(2)不带参数的构造方法

 public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

(3)带参数Collection的构造方法

 public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

参数c为一个Collection,Collection的实现类大概有以下几种常用类型:

  • List:元素可以重复的容器
  • Set: 元素不可重复的容器
  • Queue:结构是一个队列,先进先出

    这个构造方法的意思是,将一个Collection实现类的对象转换为一个ArrayList,但是c容器装的内容必须为ArrayList装的内容的子类。例如,将一个装了String内容的HashSet转换为装了String内容的ArrayList,使得ArrayList的大小和值数组都是HashSet的大小和值数组。具体实现如下代码,首先调用c(Collection的具体实现类)的toArray方法,具体大家可以看各个实现类的toArray方法,但是大概意思都是将c容器转换为object类型的数组,因为它们的返回值都是object[]。之于下面的两个判断是当得到的elementData的类名不是Object类名的时候或者是长度为0的时候才会执行。

3、方法

(1)trimToSize()

 public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}

说明

将ArrayList的容量设置为当前size的大小。首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作,例如我们的元素个数是10个,它申请的内存空间必定会大于10,即length>size,而这个方法就是把ArrayList的内存空间设置为size,去除没有用到的null值空间。这也就是我们为什么每次在获取数据长度是都是调用list.size()而不是list.length()。(list不可调用length,因为不存在变量length)

源码详解

首先modCount是从类 java.util.AbstractList 继承的字段,这个字段主要是为了防止在多线程操作的情况下,List发生结构性的变化,什么意思呢?就是防止一个线程正在迭代,另外一个线程进行对List进行remove操作,这样当我们迭代到最后一个元素时,很明显此时List的最后一个元素为空,那么这时modCount就会告诉迭代器,让其抛出异常 ConcurrentModificationException。

如果没有这一个变量,那么系统肯定会报异常ArrayIndexOutOfBoundsException,这样的异常显然不是应该出现的(这些运行时错误都是使用者的逻辑错误导致的,我们的JDK那么高端,不会出现使用错误,我们只抛出使用者造成的错误,而这个错误是设计者应该考虑的),为了避免出现这样的异常,定义了检查。

(2)size()

 public int size() {
return size;
}

说明:返回ArrayList的大小

源码解释:直接返回size

(3)isEmpty()

 public boolean isEmpty() {
return size == 0;
}

说明:返回ArrayList是否为空

解释说明:直接返回判断size==0

(4)indexOf(Object o)

 public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

说明

对象o在ArrayList中的下标位置,如果存在返回位置i,不存在返回-1

源码解释

遍历ArrayList的大小,比较o和容器内的元素,若相等,则返回位置i,若遍历完都不相等,返回-1

(5)contails(Object o)

 public boolean contains(Object o) {
return indexOf(o) >= 0;
}

说明

是否包含对象o

源码解释

调用indexOf()方法得到下标,存在则下标>=0,不存在为-1,即只要比较下标和0的大小即可

(6)lastIndexOf(Object o)

 public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

说明

返回容器内出现o的最后一个位置

源码解释

从后向前遍历,得到第一个出现对象o的位置,不存在则返回-1

(7)clone()

 public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
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(e);
}
}

说明:返回此ArrayList实例的浅表副本

(8)toArray()

 public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}

说明

ArrayList实例转换为Array数组

源码解释

直接调用Arrays类的copyOf

(9)toArray(T[] a)

 public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

说明

将ArrayList里面的元素赋值到一个数组中去

源码解释

如果a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素;如果a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,然后把a数组的size位置赋值为空

(10)rangeCheck(int index)

 private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

说明

测试index是否越界

源码解释

如果index超出ArrayList的数组长度,就会抛出IndexOutOfBoundsException异常,注意 访问控制修饰符Private只能在同一类中使用

(11)rangeCheckForAdd(int index)

 private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

说明:测试index是否越界(add、addall操作时)

(12)get(int index)

 public E get(int index) {
rangeCheck(index);
return elementData(index);
}

说明:获取index位置的元素

源码解释

先检查是否越界,然后返回ArrayList的elementData数组index位置的元素

(13)set(int index,E element)

 public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}

说明:设置index位置的元素值为element,返回该位置之前的值

(14)ensureCapacityInternal(int minCapacity)

     private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//获取默认的容量和传入参数的较大值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

说明:得到最小扩容量

(15)ensureExplicitCapacity(int minCapacity)

 private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果最小需要空间比ElementData的内存空间要大,则需要扩容
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

说明:判断是否需要扩容

(16)grow(int minCapacity)

 // MAX_VALUE为231-1,MAX_ARRAY_SIZE 就是获取Java中int的最大限制,以防止越界
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取到ArrayList中elementData数组的内存空间长度
int oldCapacity = elementData.length;
// 扩容至原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
// 不够就将数组长度设置为需要的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 判断有没超过最大限制
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
// 并将elementData的数据复制到新的内存空间
elementData = Arrays.copyOf(elementData, newCapacity);

}

说明:帮助ArrayList动态扩容的核心方法

(17)hugeCapacity(int minCapacity)

 private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

说明:由grow(int minCapacity)调用

(18)add(E e)

 public boolean add(E e) {
// 扩容
ensureCapacityInternal(size + 1);
// 将e赋值给elementData的size+1的位置。
elementData[size++] = e;
return true;
}

说明:添加元素e

(19)add(int index,E element)

 public void add(int index, E element) {
// 判断index是否越界
rangeCheckForAdd(index);
// 扩容
ensureCapacityInternal(size + 1);
// 将elementData从index位置开始,复制到elementData的index+1开始的连续空间
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 在elementData的index位置赋值element
elementData[index] = element;
// ArrayList的大小加一
size++;

}

说明:在ArrayList的index位置,添加元素element

(20)remove(int index)

 public E remove(int index) {
// 判断是否越界
rangeCheck(index);
modCount++;
// 读取旧值
E oldValue = elementData(index);
// 获取index位置开始到最后一个位置的个数
int numMoved = size - index - 1;
if (numMoved > 0)
// 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}

说明:在ArrayList移除index位置的元素

(21)remove(Object o)

 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中移除对象为o的元素,跟indexOf方法的思想基本一致

(22)fastRemove(int index)

 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; // clear to let GC do its work
}

说明:被remove(Object o)调用

(23)clear()

 public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}

说明

设置全部元素为null值,并设置size为0

源码解释

可见clear操作并不是从空间内删除,只是设置为null值,等待垃圾回收机制来回收而已,把size设置为0,以便我们不会浏览到null值的内存空间

(24)addAll(Collection<? extend E> c)

 public boolean addAll(Collection<? extends E> c) {
// 将c转换为数组a
Object[] a = c.toArray();
// 获取a占的内存空间长度赋值给numNew
int numNew = a.length;
// 扩容至size + numNew
ensureCapacityInternal(size + numNew); // Increments modCount
// 将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew
System.arraycopy(a, 0, elementData, size, numNew);
// 将size增加numNew
size += numNew;
// 如果c为空,返回false,c不为空,返回true
return numNew != 0;

}

说明:将Collection c的全部元素添加到ArrayList中

(25)addAll(int index,Collection<? extend E> c)

 public boolean addAll(int index, Collection<? extends E> c) {
// 判断index大于size或者是小于0,如果是,则抛出IndexOutOfBoundsException异常
rangeCheckForAdd(index);
// 将c转换为数组a
Object[] a = c.toArray();
int numNew = a.length;
// 扩容至size + numNew
ensureCapacityInternal(size + numNew); // Increments modCount
// 获取需要添加的个数
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;

}

说明:从第index位开始,将c全部拷贝到ArrayList

(26)removeRange(int fromIndex,int toIndex)

 protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}

说明:Removes from this list all of the elements whose index is between

{@code fromIndex}, inclusive, and {@code toIndex}, exclusive.

可以选择继承ArrayList编写自己的List类来调用这个方法

(Protected访问控制修饰符)

(27)batchRemove(Collection<?> c, boolean complement)

 private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
// 定义一个w,一个r,两个同时右移
int r = 0, w = 0;
boolean modified = false;
try {
// r先右移
for (; r < size; r++)
// 如果c中不包含elementData[r]这个元素
if (c.contains(elementData[r]) == complement)
// 则直接将r位置的元素赋值给w位置的元素,w自增
elementData[w++] = elementData[r];
} finally {
// 防止抛出异常导致上面r的右移过程没完成
if (r != size) {
// 将r未右移完成的位置的元素赋值给w右边位置的元素
System.arraycopy(elementData, r,
elementData, w,
size - r);
// 修改w值增加size-r
w += size - r;
}
if (w != size) {
// 如果有被覆盖掉的元素,则将w后面的元素都赋值为null
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
// 修改size为w
size = w;
modified = true;
}
}
return modified;
}

说明:根据complement值,将ArrayList中包含c中元素的元素删除或者保留,被removeAll(collection<?> c)和retailAll(collection<?> c)两个方法调用

(28)removeAll(collection<?> c)

 public boolean removeAll(Collection<?> c) {
// 如果c为空,则抛出空指针异常
Objects.requireNonNull(c);
// 调用batchRemove移除c中的元素
return batchRemove(c, false);
}

说明:ArrayList移除c中的所有元素

(29)retainAll(collection<?> c)

 public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
// 调用batchRemove保留c中的元素
return batchRemove(c, true);
}

说明:和removeAll相反,仅保留c中所有的元素

(30)iterator()

 public Iterator<E> iterator() {
return new Itr();
}

说明:返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator接口

(31)listIterator()

 public ListIterator<E> listIterator() {
return new ListItr(0);
}

说明:返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator接口

(32)listIterator(int index)

 public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}

说明:返回一个从index开始的ListIterator对象

(33)subList(int fromIndex,int toIndex)

 public List<E> subList(int fromIndex, int toIndex) {
// 检查异常
subListRangeCheck(fromIndex, toIndex, size);
// 调用SubList类的构造方法
return new SubList(this, 0, fromIndex, toIndex);
}

说明:根据两个参数,获取到一个子序列

(34)subListRangeCheck(int fromIndex, int toIndex, int size)

 static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}

说明:根据输入的不合理参数抛出异常

(35)sort(Comparator<? super E> c)

 public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}

说明:将列表中的值排序使用方法如下(匿名内部类):

 arrayList.sort(new Comparator<E>() {
@Override
public int compare(E o1, E o2)
return o1.compareTo(o2);//Integer使用
}
});

(36)writeObject(java.io.ObjectOutputStream s)

 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 size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// 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();
}
}

(37)readObject(java.io.ObjectInputStream s)

 private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}

(42)outOfBoundsMsg(int index)

 private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}

4、内部类

ArrayList有四个内部类,

Itr

其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(),next(),remove()等方法;

ListItr

其中的ListItr继承Itr,实现了ListIterator接口,同时重写了hasPrevious(),nextIndex(),

previousIndex(),previous(),set(E e),add(E e)等方法,所以这也可以看出了Iterator和ListIterator的区别,就是ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。

SubList

其中的SubList继承AbstractList,实现了RandmAccess接口,得到子序列类内部实现了对子序列的增删改查等方法,但它同时也充分利用了内部类的优点,就是共享ArrayList的全局变量,例如检查器变量modCount,数组elementData等,所以SubList进行的增删改查操作都是对ArrayList的数组进行的,并没有创建新的数组

ArrayListSpliterator

并行遍历,区分于Iterator的顺序遍历

该方法会把当前元素划分一部分出去创建一个新的Spliterator作为返回,两个Spliterator变会并行执行,如果元素个数小到无法划分则返回null

二、ArrayList的动态扩容机制

根据上面的ArrayList源码可知,ArrayList分三个构造函数,分别对应不同的扩容机制

1、无参构造

初始化的时候,elementData的数组长度为0,现在添加数据

 public boolean add(E e) {
//确保内部容量(通过判断,如果够则不进行操作;容量不够就扩容来确保内部容量)
ensureCapacityInternal(size + 1); // ①Increments modCount!!
elementData[size++] = e;//②
return true;
}

得到最小扩容量(最小需要容量)

private void ensureCapacityInternal(int minCapacity) {
//如果实际存储数组 是空数组,则最小需要容量就是默认容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}

如果数组elementData的长度小于最小需要的容量(minCapacity)就扩容

   private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果数组(elementData)的长度小于最小需要的容量(minCapacity)就扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

扩容的核心方法

/*
*增加容量,以确保它至少能容纳
*由最小容量参数指定的元素数。
* @param mincapacity所需的最小容量
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//>>位运算,右移动一位。 整体相当于newCapacity =oldCapacity + 0.5 * oldCapacity int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 最重要的复制元素方法
elementData = Arrays.copyOf(elementData, newCapacity);
}

总结:

ArrayList在没有指定initialCapacity时就是会使用延迟分配数组空间,当第一次插入元素时才分配默认10个对象空间,下一次需要扩容的时候就会按照1.5倍增长(位运算)

关于Arrays.copyOf(T[] original, int newLength)

    public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
} /**
* @Description 复制指定的数组, 如有必要用 null 截取或填充,以使副本具有指定的长度
* 对于所有在原数组和副本中都有效的索引,这两个数组相同索引处将包含相同的值
* 对于在副本中有效而在原数组无效的所有索引,副本将填充 null,当且仅当指定长度大于原数组的长度时,这些索引存在
* 返回的数组属于 newType 类 * @param original 要复制的数组
* @param 副本的长度
* @param 副本的类
*
* @return 原数组的副本,截取或用 null 填充以获得指定的长度
* @throws NegativeArraySizeException 如果 newLength 为负
* @throws NullPointerException 如果 original 为 null
* @throws ArrayStoreException 如果从 original 中复制的元素不属于存储在 newType 类数组中的运行时类型 * @since 1.6
*/
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
} 参数说明:
src:源对象
srcPos:源数组中的起始位置
dest:目标数组对象
destPos:目标数据中的起始位置
length:要拷贝的数组元素的数量
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);

从代码可知,数组拷贝时调用的是本地方法 System.arraycopy() ;

Arrays.copyOf()方法返回的数组是新的数组对象,原数组对象仍是原数组对象,不变,该拷贝不会影响原来的数组。

2、带初始容量的构造函数

分两种情况:

一种是指定容量为0,指定为0的话,添加第一个元素扩容后,elementData的容量为1,继续添加元素,又需要扩容,容量变为1.5倍,所以不推荐指定为0

第二种情况就是指定不为0,然后就直接在构造函数指定了数组容量,然后当所需的最小容量大于数组容量时就会扩容,扩容机制跟上述一样,

三、ArrayList与LinkedList的区别

  • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构
  • 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针
  • 对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据

四、ListIterator与Iterator的详解

在使用Java集合的时候,都需要使用Iterator。但是java集合中还有一个迭代器ListIterator,在使用List、ArrayList、LinkedList和Vector的时候可以使用。

Iterator迭代器包含的方法

hasNext():如果迭代器指向位置后面还有元素,则返回 true,否则返回false

next():返回集合中Iterator指向位置后面的元素

remove():删除集合中Iterator指向位置后面的元素

ListIterator迭代器包含的方法

add(E e): 将指定的元素插入列表,插入位置为迭代器当前位置之前

hasNext():以正向遍历列表时,如果列表迭代器后面还有元素,则返回 true,否则返回false

hasPrevious():如果以逆向遍历列表,列表迭代器前面还有元素,则返回 true,否则返回false

next():返回列表中ListIterator指向位置后面的元素

nextIndex():返回列表中ListIterator所需位置后面元素的索引

previous():返回列表中ListIterator指向位置前面的元素

previousIndex():返回列表中ListIterator所需位置前面元素的索引

remove():从列表中删除next()或previous()返回的最后一个元素(有点拗口,意思就是对迭代器使用hasNext()方法时,删除ListIterator指向位置后面的元素;当对迭代器使用hasPrevious()方法时,删除ListIterator指向位置前面的元素)

set(E e):从列表中将next()或previous()返回的最后一个元素返回的最后一个元素更改为指定元素e

主要区别

  • 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。

  • ListIterator有add方法,可以向List中添加对象,而Iterator不能。

  • ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。

  • ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

  • 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。

java集合类之ArrayList详解的更多相关文章

  1. 【Java集合类】ArrayList详解 (JDK7)

    相信对于使用过Java的人来说,ArrayList这个类大家一定不会陌生. 数据结构课上讲过, Array是数组,它能根据下标直接找到相应的地址,所以索引速度很快,但是唯一的缺点是不能动态改变数组的长 ...

  2. java集合类之LinkedList详解

    一.LinkedList简介 由于LinkedList是一个实现了Deque的双端队列,所以LinkedList既可以当做Queue,又可以当做Stack,在将LinkedList当做Stack时,使 ...

  3. java集合(arraylist详解)

    一.ArrayList概述 ArrayList是实现List接口的动态数组,所谓动态就是它的大小是可变的.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类 ...

  4. ArrayList详解-源码分析

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

  5. Java 8 Stream API详解--转

    原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...

  6. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  7. 【Java集合】LinkedList详解前篇

    [Java集合]LinkedList详解前篇 一.背景 最近在看一本<Redis深度历险>的书籍,书中第二节讲了Redis的5种数据结构,其中看到redis的list结构时,作者提到red ...

  8. [转载]java中import作用详解

    [转载]java中import作用详解 来源: https://blog.csdn.net/qq_25665807/article/details/74747868 这篇博客讲的真的很清楚,这个作者很 ...

  9. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

随机推荐

  1. STM32F 系列单片机 调试记录

    1.RTC 配置 调一个 RTC,刚开始运行都正常,设置的时间跟读出的时间一样.但是换了一个芯片出现读出的年不对的情况,调试才发现是RTC设置的时候有些参数漏掉没填导致的. T_S32 DRIVER_ ...

  2. Django-下载安装-配置-创建django项目-三板斧简单使用

    目录 Django 简介 使用 django 的注意事项 计算机名不能有中文 Django版本问题 django下载安装 在命令行下载安装 在pycharm图形界面下载安装 检验是否安装成功 创建Dj ...

  3. ie表单提交提示下载文件

    使用jquery的ajaxform提交form表单 如果在html中多了   enctype ="multipart/form-data"   属性值 提交时就会在ie8中提示下载 ...

  4. Java虚拟机原理和调优

    https://blog.csdn.net/sun1021873926/article/details/78002118 115道Java经典面试题(面中率最高.最全) 史上最全 40 道 Dubbo ...

  5. 个人IP「Android大强哥」上线啦!

    自从入职新公司之后就一直忙得不行,一边熟悉开发的流程,一边熟悉各种网站工具的使用,一边又在熟悉业务代码,好长时间都没有更文了. 不过新公司的 mentor(导师)还是很不错的,教给我很多东西,让我也能 ...

  6. C#中Path类的常用方法

    场景 打开VS,输入Path,我们可以看到其定义. 都是静态方法,所以我们可以使用类名直接调用. 实现 新建命令行程序,编码如下: string str = @"C:\Users\Admin ...

  7. springboot postman 对象里传时间格式问题

    主要问题是系列化的问题,在定义时间变量处使用如下的注解即可.导包注意了······ 如果springmvc使用的是com.fasterxml.jackson 的jar包则直接使用一下注解即可 impo ...

  8. 算法与数据结构基础 - 图(Graph)

    图基础 图(Graph)应用广泛,程序中可用邻接表和邻接矩阵表示图.依据不同维度,图可以分为有向图/无向图.有权图/无权图.连通图/非连通图.循环图/非循环图,有向图中的顶点具有入度/出度的概念. 面 ...

  9. 渐进深入理解Nginx

    文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 之前其实写过一篇文章具体介绍过:最基础的Nginx教学,当时有提到过Nginx有一个重要的功能:负载均衡.所以 ...

  10. 运用 CSS in JS 实现模块化

    一.什么是 CSS in JS 上图来源:https://2019.stateofcss.com/technologies/ CSS in JS 是2014年推出的一种设计模式,它的核心思想是把 CS ...