Arrays.asList將一個數組轉換爲 List,不再重複造輪子

一、基礎使用

方式一:

String[] myArray = { "Apple", "Banana", "Orange" }; 
List<String> myList = Arrays.asList(myArray);

方式二:

List<String> myList = Arrays.asList("Apple", "Orange");

二、瞭解源碼

    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

1、數組的類型只能是包裝類     

       注意:參數類型是 T ,根據官方文檔的描述,T 是數組元素的 class
  如果你對反射技術比較瞭解的話,那麼 class 的含義想必是不言自明。我們知道任何類型的對象都有一個 class 屬性,這個屬性代表了這個類型本身。原生數據類型,比如 int,short,long等,是沒有這個屬性的,具有 class 屬性的是它們所對應的包裝類 Integer,Short,Long。

如果需要將一個整型數組轉換爲 List,那麼就將數組的類型聲明爲 Integer 而不是 int。

public class Test {
   public static void main(String[] args) {
      Integer[] myArray = { 1, 2, 3 };
      List myList = Arrays.asList(myArray);
      System.out.println(myList.toString());
   }
}

2、asList返回的List不允許擴容

我們知道 List 是可以動態擴容的,因此在創建一個 List 之後最常見的操作就是向其中添加新的元素或是從裏面刪除已有元素:

public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List<String> myList = Arrays.asList(myArray);
      myList.add("Guava");
   }
}

嘗試運行這段代碼,結果拋出了一個 java.lang.UnsupportedOperationException 異常!這一異常意味着,向 myList 添加新元素是不被允許的;如果試圖從 myList 中刪除元素,也會拋出相同的異常。爲什麼會如此?
仔細閱讀官方文檔,你會發現對 asList 方法的描述中有這樣一句話:

返回一個由指定數組生成的固定大小的 List。

看上面的源碼可知,asList()方法中的的確確生成了一個 ArrayList ,這不應該是支持動態擴容的嗎?彆着急,接着往下看。緊跟在 asList 方法後面,有這樣一個內部類:

    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return Arrays.copyOf(a, a.length, Object[].class);
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

錯誤理解:

ArrayList內部類中有一個被聲明爲 final 的數組 a ,所有傳入的元素都會被保存在這個數組 a 中。到此,謎底又揭曉了: asList 方法返回的確實是一個 ArrayList ,但這個 ArrayList 並不是 java.util.ArrayList ,而是 java.util.Arrays 的一個內部類。這個內部類用一個 final 數組來保存元素,因此用 asList 方法產生的 ArrayList 是不可修改大小的。

正確理解:

ArrayList繼承了AbstractList<E>,平時我們使用的都是ArrayList的add方法,它是進行了重寫;所以根本原因在於Arrays的內部類ArrayList沒有重寫add方法,而在AbstractList中U對add方法天然就會拋出異常“throw new UnsupportedOperationException();”。final只是代表不能更改引用指向,對象本身是可以增加元素的。

解決方案:創建一個真正的 ArrayList

  既然我們已經知道之所以asList 方法產生的 ArrayList 不能修改大小,是因爲這個 ArrayList 並不是“貨真價實”的 ArrayList ,那我們就自行創建一個真正的 ArrayList :

public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List<String> myList = new ArrayList<String>(Arrays.asList(myArray));
      myList.add("Guava");
   }
}

 三、你造的輪子 

public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List<String> myList = new ArrayList<String>();
      for (String str : myArray) {
         myList.add(str);
      }
      System.out.println(myList.size());
   }
}

這麼做自然也是可以達到目的的,但顯然有一個缺點:代碼相對冗長,而且這麼做其實無異於自己造輪子(reinventing the wheel)。當然了,自己實現方法的好處也是顯而易見的,不管有什麼需求,自己來滿足就好了,畢竟自己動手豐衣足食嘛。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章