####關於Arrays.asList(T)這個API 原

####關於Arrays.asList(T)這個API

參考: https://docs.oracle.com/javase/tutorial/java/generics/why.html https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

所以會研究這個問題,是因爲在寫代碼的時候遇到了這個,很反直覺. 同樣都是{120,130}竟然返回了不同的類型.

    public static void main(String[] args) {
        Integer[] pangs = {120, 130};
        int[] fats = {120, 130};
        List<Integer> pangList = Arrays.asList(pangs);
        List<int[]> fatsList = Arrays.asList(fats);
    }

Auto boxing is the automatic conversion that the Java compiler makes, between the primitive types and their corresponding object wrapper classes.

Generic Types A generic type is a generic class or interface that is parameterized over types.

以下是對返回類型推斷的一些解釋(軍功章的一半分給石五花), 首先明確兩點

  1. auto boxing unboxing是對基本數據類型及其包裝類型來說的.
  2. generic type 是對class或者interface來說的.

然後看傳入Arrays.asList(fats)的fats的類型是int[] 注意int[]並不是基本數據類型, 基本數據類型是一回事而,基本數據類型的數組又是另外一回事. 所以這裏並沒有想當然的auto boxing發生.

接着就是vargs, ...通常在編譯時會轉變成對應的一維數組 對應這裏的上下文即int[][] 數據類型爲int[]的一維數組 所以返回的類型就是List<int[]>


編譯時類型是List,但是運行時的類型是java.util.Arrays.ArrayList.

String[] str = {"hello","world"}
List<String> listStr = Arrays.asList(str);
//這裏就要拋異常了
listStr.add("shit")
  * 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}.
     * @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);
    }

重點就是這兩句: Returns a fixed-size list backed by the specified array. return a list view of the specified array.

This method acts as bridge between array-based and collection-based APIs. 把原先基於數組的改成基於collection的,方便你可能會調用一些collection相關的API.

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

這個代碼命名很雞賊,就叫的ArrayList. 注意這裏的ArrayList可不是那個常用的--->java.util.ArrayList. 它是---->java.util.Arrays.ArrayList. 然後看它代碼的實現.聲明長這個樣子

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable{
          ...
        }

java.util.AbstractList這個類的聲明

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
public abstract class AbstractCollection<E> implements Collection<E> 

這是java.util.List這個類的聲明

public interface List<E> extends Collection<E> { ... }        

這就是爲啥你在外面可以用List來接,你懂我意思.

Exception in thread "main" java.lang.UnsupportedOperationException 至於那個異常,是java.util.AbstractList拋出的,它壓根就沒有實現. 你的java.util.ArrayList可以這麼幹是因爲它自己實現了.

這是AbstractList類的add方法

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

####問題來了,爲什麼Java要把它設計成fixed-size的呢?

  • 因爲這個API的作用僅僅acts as bridge between array-based and collection-based APIs
  • 數組本來就不可以變啊,你懂我意思吧,不要擡槓. 我說不可變的意思你懂吧,但是數組裏的元素是可以變化的. 起碼數組的大小什麼的是不可以變的.嗯 數組本來就是fixed-size的. 事實上java.util.Arrays.ArrayList裏是提供了相應的API比如set,get什麼的.
       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;
        }

只要不動大小怎麼着都可以. 如果你改變數組的大小了,就不是原來那個數組了.

可是如果就是想要一個不fixed-size的List的話,可以這麼着

int[] fats = {120,130};
new ArrayList(Arrays.asList(fats));

這把返回的就是常用的java.util.ArrayList了.

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