千萬不要這樣使用 Arrays.asList !

使用Arrays.asList()的緣由無非是想將數組或一些元素轉爲集合,而你獲得的集合並不必定是你想要的那個集合。java

而一開始asList()的設計時用於打印數組而設計的,但jdk1.5開始,有了另外一個比較更方便的打印函數Arrays.toString(),因而打印再也不使用asList(),而asList()恰巧可用於將數組轉爲集合。面試

錯誤用法

若是你這樣使用過,那你要注意下了。數組

  • 錯誤一

將基本類型數組做爲asList的參數微信

int[] arr = {1,2,3};
List list = Arrays.asList(arr);
System.out.println(list.size());

猜一下輸出結果?架構

  • 錯誤二

將數組做爲asList參數後,修改數組或Listdom

String[] arr = {"歡迎","關注","Java"};
List list = Arrays.asList(arr);
    
arr[1] = "愛上";
list.set(2,"我");
    
System.out.println(Arrays.toString(arr));
System.out.println(list.toString());

猜一下輸出結果?ide

  • 錯誤三

數組轉換爲集合後,進行增刪元素函數

String[] arr = {"歡迎","關注","Java"};
List list = Arrays.asList(arr);
    
list.add("新增");
list.remove("關注");

猜一下輸出結果?工具

你是否是覺得上面👆那個list是 java.util.ArrayList ?ui

答案很肯定:NO!
吃驚.jpg

探索真理

咱們經過asList()源碼可發現,但爲了更直觀,咱們經過IDEA debug來看看結果。

List<String> asList = Arrays.asList("歡迎","關注","碼上實戰");
ArrayList<String> aList = new ArrayList<>(asList);

debug-list.png

其實它返回的是 java.util.Arrays.ArrayList ,這個傢伙是誰呢?

表演.jpg

請看下源碼:

public class Arrays {
    
    //省略其餘方法
    
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }
        
    //就是這個傢伙             👇
    private static class ArrayList<E> extends AbstractList<E>
            implements RandomAccess, java.io.Serializable{
    
        private final E[] a;
    
        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }
    
        @Override
        public int size() {
            return a.length;
        }
        //省略其餘方法
    }
}

但它和ArrayList貌似很像唉!有什麼不一樣嗎?

不一樣之處

Arrays.ArrayList 是工具類 Arrays 的一個內部靜態類,它沒有徹底實現List的方法,而 ArrayList直接實現了List 接口,實現了List全部方法。

list對比.png

  • 長度不一樣 和 實現的方法不一樣

    Arrays.ArrayList是一個定長集合,由於它沒有重寫add,remove方法,因此一旦初始化元素後,集合的size就是不可變的。

  • 參數賦值方式不一樣

Arrays.ArrayList將外部數組的引用直接經過「=」賦予內部的泛型數組,因此本質指向同一個數組。

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

ArrayList是將其餘集合轉爲數組後copy到本身內部的數組的。

public ArrayList(Collection<? extends E> c) {
    // toArray 底層使用的是 數組clone 或 System.arraycopy
    elementData = c.toArray();
}

揭曉答案

  • 錯誤一

    因爲Arrays.ArrayList參數爲可變長泛型,而基本類型是沒法泛型化的,因此它把int[] arr數組當成了一個泛型對象,因此集合中最終只有一個元素arr.

  • 錯誤二

    因爲asList產生的集合元素是直接引用做爲參數的數組,因此當外部數組或集合改變時,數組和集合會同步變化,這在平時咱們編碼時可能產生莫名的問題。

  • 錯誤三

    因爲asList產生的集合並無重寫add,remove等方法,因此它會調用父類AbstractList的方法,而父類的方法中拋出的倒是異常信息。

支持基礎類型的方式

  • 若是使用Spring
int[]  a = {1,2,3};
List list = CollectionUtils.arrayToList(a);
System.out.println(list);
  • 若是使用Java8
int intArray[] = {1, 2, 3};
List<Integer> iList = Arrays.stream(intArray)
                            .boxed()
                            .collect(Collectors.toList());
System.out.println(iList);

數組轉爲ArrayList

  • 遍歷轉換
Integer intArray[] = {1, 2, 3};
ArrayList<Integer> aList = new ArrayList<>();
for (Integer i: intArray){
    aList.add(i);
}

顯然這種方式不夠優雅!反正我不肯意使用。

  • 使用工具類

    上面方案不夠優雅,那麼這種相對來講優雅一些。

List<String> list = new ArrayList(); 
Collections.addAll(list, "welcome", "to", "china");
你覺得這種還不錯?
too young too simple!
addAll()方法的實現就是用的上面遍歷的方式。
  • 若是使用Java8

    既能夠用於基本類型也能夠返回想要的集合。

int intArray[] = {1, 2, 3};
List<Integer> iList = Arrays.stream(intArray)
                            .boxed()
                            .collect(Collectors.toList());
System.out.println(iList);
  • 兩個集合類結合

    將Arrays.asList返回的集合做爲ArrayList的構造參數

ArrayList arrayList = new ArrayList<>(Arrays.asList("welcome", "to", "china"));

最後

勿以點小而不聞!體現程序素養或許就在這些小地方,不要給本身或別人留坑。

那麼這個知識點,你get到了嗎?get到了,那來繼續關注我。沒get到?來來來,咱倆單獨聊聊。

往期文章一覽

把「策略模式」應用到實際項目中

造個輪子,我學到了什麼

技術面試中的軟技能

不一樣時重寫equals和hashCode又怎樣!

關注微信公衆號 「碼上實戰」 回覆 :面試視頻 和 架構師 送你很是不錯的資料!

相關文章
相關標籤/搜索