使用ArrayList.subList()和Arrays.asList()方法要注意的地方

一. ArrayList.subList()方法

  1. ArrayList.subList(int fromIndex, int toIndex)方法返回一個List: 此List的值包含fromIndex所在的值, 但不包含toIndex所在的值. 如果fromIndex等于toIndex, 那么會返回一個沒有任何元素的空List. 返回的List支持java.util.List接口的所有操作.

  2. **ArrayList.subList() 方法返回的List不能強轉為ArrayList. **
    ArrayList.subList() 方法返回的List實際類型是ArrayList的一個內部類SubList, 即java.util.ArrayList$SubList

  3. ArrayList.subList() 方法返回的List是ArrayList中某段數據的一個視圖. 因此, 在操作此方法返回的List時, 同樣會改變ArrayList的數據. 我們來看看ArrayList.SubList這個類的幾個方法就知道了:

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;
}
public E get(int index) {
    rangeCheck(index);
    checkForComodification();
    return ArrayList.this.elementData(offset + index);
}

我們知道ArrayList的內部是用對象數組(成員: elementData)存儲數據的, 可以看到ArrayList的內部類SubList的add和get方法操作的就是ArrayList內部的對象數組. 因此對ArrayList.subList()方法的返回值的任何操作都會反映到ArrayList對象本身.

  1. 如果原ArrayList對象有改動, 那么ArrayList.subList()方法返回的視圖將會無效. 也就是說在操作ArrayList.subList()方法的返回值前不能對原ArrayList做任何修改, 否則你將得到一個java.util.ConcurrentModificationException異常.

  2. ArrayList的subList方法定義如下:

/**
     * Returns a view of the portion of this list between the specified
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
     * empty.)  The returned list is backed by this list, so non-structural
     * changes in the returned list are reflected in this list, and vice-versa.
     * The returned list supports all of the optional list operations.
     *
     * <p>This method eliminates the need for explicit range operations (of
     * the sort that commonly exist for arrays).  Any operation that expects
     * a list can be used as a range operation by passing a subList view
     * instead of a whole list.  For example, the following idiom
     * removes a range of elements from a list:
     * <pre>
     *      list.subList(from, to).clear();
     * </pre>
     * Similar idioms may be constructed for {@link #indexOf(Object)} and
     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
     * {@link Collections} class can be applied to a subList.
     *
     * <p>The semantics of the list returned by this method become undefined if
     * the backing list (i.e., this list) is <i>structurally modified</i> in
     * any way other than via the returned list.  (Structural modifications are
     * those that change the size of this list, or otherwise perturb it in such
     * a fashion that iterations in progress may yield incorrect results.)
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

更多細節可參考JDK中java.util.ArrayList類的源碼

二. Arrays.asList()方法

  1. Arrays.asList(T ... args)方法將一個數組轉換成一個List. Arrays.asList()方法返回的對象是Arrays類的一個內部類, 并沒有實現修改集合的相關方法 (看源碼可以知道java.util.Arrasy$ArrayList類支持set()方法, 所以還是可以修改的). Arrays.asList()體現的是適配器模式, 只是轉換接口, 后臺數據仍是被轉換的數組. 因此: 對原數組的改動會影響返回的List, 反之亦然!!
  2. 看源碼可以知道Arrays.asList()的返回值是ArrayList, 但是請注意, 此ArrayList是Arrays類的一個內部類(java.util.Arrays$ArrayList), 而不是java.util.ArrayList. 因此不要把返回值強轉成java.util.ArrayList
  3. Arrays.asList()方法的返回值不支持add/remove/clear方法 (返回的List沒有實現修改操作), 如果調用, 你會得到一個UnsupportedOperationException異常.
  4. Arrays.asList()方法定義如下:
/**
 * Returns a fixed-size list backed by the specified array.  (Changes to
 * the returned list "write through" to the array.)  This method acts
 * as bridge between array-based and collection-based APIs, in
 * combination with {@link Collection#toArray}.  The returned list is
 * serializable and implements {@link RandomAccess}.
 *
 * <p>This method also provides a convenient way to create a fixed-size
 * list initialized to contain several elements:
 * <pre>
 *     List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
 * </pre>
 *
 * @param <T> the class of the objects in the array
 * @param a the array by which the list will be backed
 * @return a list view of the specified array
 */
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

此方法主要作用是: 用已存在的數組初始化一個固定大小的List.

三. 總結

  1. 對API使用有疑問的話, 最好是去看源碼(如果有源碼) 或 API文檔.
  2. 定期閱讀JDK源碼 (把其中常用的API吃透, 也就不會出現由于對API理解有誤而導致的錯誤!!)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容