ArrayList的 subList ( int fromIndex, int toIndex ) 方法执行结果是获取ArrayList的一部分,返回的是ArrayList的部分视图。《阿里巴巴Java开发手册》中对subList方法的使用有规定:

首先通过一个例子,初步了解subList的用法和易出错的地方:
import java.util.ArrayList;
import java.util.List;
public class SubListDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println("原:" + list);
List<Integer> subList = list.subList(0, 5);
System.out.println("子:" + subList);
// subList的add()方法
subList.add(3, 21);
// 输出原集合
System.out.println("==============subList的add()方法执行结果====================");
System.out.println("原:" + list);
// 输出subList
System.out.println("子:" + subList);
// ArrayList的add()方法
list.add(31);
// 输出原集合
System.out.println("==============ArrayList的add()方法执行结果====================");
System.out.println("原:" + list);
// 输出subList
System.out.println("子:" + subList);
}
}
程序的执行结果为:
从结果得出:
- 对子类subList的操作会反映到父类中。
- 使用父类的方法(能改变modCount值的方法)修改集合会导致子类的遍历抛出 ConcurrentModificationException 异常。
程序的执行结果也验证了阿里手册的规定,下面,通过源码解析更加清晰的理解这两条规定的用意。
ArrayList 的 subList 方法返回的一个内部类 SubList,返回的 List 中,下标范围在[fromIndex, toIndex) 之间:
public List<E> subList(int fromIndex, int toIndex) {
// 参数检查
subListRangeCheck(fromIndex, toIndex, size);
// 内部类SubList,this为父类的引用,0 表示父类下标偏移量
return new SubList(this, 0, fromIndex, toIndex);
}
subListRangeCheck(fromIndex, toIndex, 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 + ")");
}
SubList 内部类,继承了 AbstractList 类,并实现了 RandomAccess 接口,支持随机读取:
/*
* SubList返回的视图是由父类集合支持的,因此是非结构化的
* 所以,对SubList子集合进行操作,也会修改父类的集合。
* SubList类中,每个public方法(除了subList()方法)都调用checkForComodification()
* 用于判断父类集合是否被修改
* 所以,如果直接使用父类方法修改集合,则SubList子类的遍历、增加、删除等操作都会抛出异常
*/
private class SubList extends AbstractList<E> implements RandomAccess {
// 父类的引用
private final AbstractList<E> parent;
/*
* 父类集合中的位置,如果使用SubList中的subList方法,
* 则此时父类为SubList类,不是ArrayList
*/
private final int parentOffset;
// 子类List在父类 ArrayList 中的下标位置
private final int offset;
// 视图集合的size
int size;
// 构造方法,参数offset表示父类集合的下标偏移量
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
public E set(int index, E e) {
// 检查下标是否越界,这里index的值在[0, this.size)之间,size = toIndex - fromIndex
rangeCheck(index);
// 检查是否有其他线程修改了父类集合
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
// 调用父类方法替换元素,所以本质上还是在父类集合中替换元素
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}
public E get(int index) {
// 检查下标是否越界,这里index的值在[0, this.size)之间
rangeCheck(index);
checkForComodification();
// 调用父类方法获取元素
return ArrayList.this.elementData(offset + index);
}
public int size() {
checkForComodification();
return this.size;
}
public void add(int index, E e) {
// 检查下标,index的值在[0, this.size]之间
rangeCheckForAdd(index);
checkForComodification();
// 使用父类方法添加元素,下标位置为parentOffset + index, 在父类集合添加元素。
parent.add(parentOffset + index, e);
// 父类add()方法修改了modCount的值,更新subList的modCount值
this.modCount = parent.modCount;
this.size++;
}
// 根据下标移除元素
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
// 移除指定区间的元素
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
parent.removeRange(parentOffset + fromIndex,
parentOffset + toIndex);
this.modCount = parent.modCount;
this.size -= toIndex - fromIndex;
}
public boolean addAll(Collection<? extends E> c) {
return addAll(this.size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
parent.addAll(parentOffset + index, c);
this.modCount = parent.modCount;
this.size += cSize;
return true;
}
// subList 中迭代器使用ListIterator(),迭代器的源码已分析
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
final int offset = this.offset;
return new ListIterator<E>() {
int cursor = index;
int lastRet = -1;
int expectedModCount = ArrayList.this.modCount;
public boolean hasNext() {
return cursor != SubList.this.size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
// offset + index 的下标为此时subList中元素在父类集合中的位置
return (E) elementData[offset + (lastRet = i)];
}
public boolean hasPrevious() {
return cursor != 0;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[offset + (lastRet = i)];
}
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = SubList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[offset + (i++)]);
}
// update once at end of iteration to reduce heap write traffic
// 与 Itr 中不同
lastRet = cursor = i;
checkForComodification();
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
SubList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(offset + lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
SubList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
// 检查是否有多线程修改集合
final void checkForComodification() {
if (expectedModCount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
};
}
// 内部方法
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, offset, fromIndex, toIndex);
}
// 下标越界检查
private void rangeCheck(int index) {
if (index < 0 || index >= this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 下标越界检查,仅add()方法和addAll()方法使用
private void rangeCheckForAdd(int index) {
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 下标越界异常信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+this.size;
}
// 是否有多线程修改集合
private void checkForComodification() {
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
}
// 下篇文章讲解
public Spliterator<E> spliterator() {
checkForComodification();
return new ArrayListSpliterator<E>(ArrayList.this, offset,
offset + this.size, this.modCount);
}
}
关于 parentOffset 和 offset :

本文通过实例分析ArrayList的subList方法,探讨其用法和潜在风险,包括子列表操作影响父列表以及使用父列表方法修改集合导致的ConcurrentModificationException异常。通过对源码的解读,揭示subList内部实现及边界检查机制。
1523

被折叠的 条评论
为什么被折叠?



