我們經常使用subString方法來對String對象進行分割處理,同時我們也可以使用subList、subMap、subSet來對List、Map、Set進行分割處理,但是這個分割存在某些瑕疵。
一、subList返回僅僅只是一個視圖
首先我們先看如下實例:
public static void main(String[] args) { List<Integer> list1 = new ArrayList<Integer>(); list1.add(1); list1.add(2); //通過構造函數新建一個包含list1的列表 list2 List<Integer> list2 = new ArrayList<Integer>(list1); //通過subList生成一個與list1一樣的列表 list3 List<Integer> list3 = list1.subList(0, list1.size()); //修改list3 list3.add(3); System.out.println("list1 == list2:" + list1.equals(list2)); System.out.println("list1 == list3:" + list1.equals(list3)); }
這個例子非常簡單,無非就是通過構造函數、subList重新生成一個與list1一樣的list,然后修改list3,最后比較list1 == list2?、list1 == list3?。按照我們常規的思路應該是這樣的:因為list3通過add新增了一個元素,那么它肯定與list1不等,而list2是通過list1構造出來的,所以應該相等,所以結果應該是:
list1 == list2:true list1 == list3: false
首先我們先不論結果的正確與否,我們先看subList的源碼:
public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); }
subListRangeCheck方式是判斷fromIndex、toIndex是否合法,如果合法就直接返回一個subList對象,注意在產生該new該對象的時候傳遞了一個參數 this ,該參數非常重要,因為他代表着原始list。
/** * 繼承AbstractList類,實現RandomAccess接口 */ 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; } //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; } //get方法 public E get(int index) { rangeCheck(index); checkForComodification(); return ArrayList.this.elementData(offset + index); } //add方法 public void add(int index, E e) { rangeCheckForAdd(index); checkForComodification(); parent.add(parentOffset + index,