Java:List集合中SubList

    技术2022-07-11  102

    开始前不妨在心里默算下以下的输出是什么?List集合的subList方法返回的到底是什么?

    public static void main(String[] args) { List<Integer> list = Arrays.asList(0, 1, 2); System.out.println("before:" + list); truncateFirst(list); System.out.println("after:" + list); } public static void truncateFirst(List<Integer> list) { list = list.subList(1, list.size()); System.out.println("doing:" + list); }

    这里先用工具类Arrays.asList方法创建了一个实现为ArrayList的list集合,使用者本想,传递了一个引用到truncateFirst方法,并将修改的list赋给原本的引用对象,然后在方法返回后一切又“恢复”了。

    显然,上述结果似乎有点出乎使用者的本意,然而当你了解subList方法返回的仅是原对象的视图时,一切又是情理之中。

    当你进入ArrayList内部,你会发现SubList仅仅是其一个内部类,这个内部类

    持有对原ArrayList的引用持有原ArrayList对象的offset,size持有原对象的modCount 删繁就简后,ArrayList和SubList的关系大概是这样的: public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { // non-private to simplify nested class access transient Object[] elementData; // The size of the ArrayList (the number of elements it contains). private int size; // subList方法首先检查了取址范围,然后开始创建内部类 public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); } private class SubList extends AbstractList<E> implements RandomAccess { private final AbstractList<E> parent; private final int parentOffset; private final int offset; int size; 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; } //针对SubList的其他操作 } //List集合的 set, get, addAll ... }

    因此,你发现你的subList仅仅是创建了一个可以称之为“视图”的内部类,它并没有修改ArrayList的,因此:list = list.subList(1, list.size()); 不会修改本身(this)对象的引用。

    但是如果试图修改SubList,会影响原来的ArrayList吗?

    public static void truncateFirst(List<Integer> list) { list = list.subList(1, list.size()); list.set(0, 100); }

    答案是:会!

    内部类SubList的set方法是这样实现的

    public E set(int index, E e) { rangeCheck(index); checkForComodification(); E oldValue = ArrayList.this.elementData(offset + index); ArrayList.this.elementData[offset + index] = e; return oldValue; }

    可以看到set方法的操作对象是ArrayList.this,即原对象本身!

    Processed: 0.018, SQL: 9