Arrays.asList()方法


原文地址:https://blog.csdn.net/w574951402/article/details/53246777

本文是對Arrays.asList()方法從源碼角度進行分析,解析使用中的一些困惑。

首先看Arrays.asList()的源碼

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

使用該方法可以將一個變長參數或者數組轉換成List
看似很簡單但實際使用起來卻會發現存在很多問題,看下面代碼來發現問題。

問題一:基本類型數組作為參數問題

public class ArraysAsListTest {
  public static void main(String[] args) {
    int[] a = {1,2,3};
    Integer[] b = {1,2,3};

    List listA = Arrays.asList(a);
    List listA1 = Arrays.asList(1,2,3);
    List listB = Arrays.asList(b);

    System.out.println(listA.size());//out:1
    System.out.println(listA1.size());//out:3
    System.out.println(listB.size());//out:3
  }
}

嗯?用int類型的數組作為參數為什么輸出size是1呢,使用Integer類型size就是3了呢。
再看源碼,asList接收的是一個泛型變長參數,而我們知道基本類型是不能泛型化的,就是說8種基本類型不能作為泛型參數,要想作為泛型參數就要使用其所對應的包裝類。

但是listA的Size為什么是1呢,這是因為listA傳遞的是一個int類型的數組,數組是一個對象,它是可以泛型化的,也就是說例子中是把一個int類型的數組作為了T的類型,所以轉換后在List中就只有一個類型為int數組的元素。后邊ListA1與ListB也就可以理解了,一個是進行了自動打包,一個是本來就是包裝類型。

我們可以打印下list中元素類型進行驗證

System.out.println("ListA元素類型:"+listA.get(0).getClass());
//out:ListA元素類型:class [I
System.out.println("ListA元素:"+Arrays.toString((int[]) listA.get(0)));
//ListA元素:[1, 2, 3] 該處是為了驗證list中元素
System.out.println("ListA1元素類型:"+listA1.get(0).getClass());
//out:ListA1元素類型:class java.lang.Integer
System.out.println("ListB元素類型:"+listB.get(0).getClass());
//out:ListB元素類型:class java.lang.Integer

問題二:asList()方法返回對象使用add()方法拋出異常

public class ArraysAsListTest {
    public static void main(String[] args) {
    List<String> pets = Arrays.asList("cat","dog");
    pets.add("what");
    }
}

異常:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at ArraysAsListTest.main(ArraysAsListTest.java:9)    

What?一個List執行add方法會拋出異常,難道add方法不是List的基本用法嗎。還是來研究下asList的實現吧

查看一下Arrays.asList中使用的ArrayList到底長啥樣?

原來Arrays的asList方法使用的ArrayList類是一個內部定義的類,而不是java.util.ArrayList類。看其部分源碼

public class Arrays { 
....... 

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) { 
if (array==null) 
throw new NullPointerException(); 
a = array; 
} 

...... 
} 
}

這個靜態內部類,存儲數組元素的a變量是final類型的,由此判斷,這個靜態內部類是不能做任何內部元素的添加刪除操作的!就跟String類一樣,String對象存儲字符數組的變量也是有final修飾符的。因為一旦增加數組元素,這個數組容量已經定好的容器就無法裝載增加的元素了。

內部類里面並沒有add,remove方法,可以看下這個類繼承的AbstractList類里面對這些方法的實現

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

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

public E remove(int index) { 
throw new UnsupportedOperationException(); 
} 
}

Ok!找到異常的來源了,我們使用asList得到的對象add、remove方法直接就是拋出異常

如果要對asList得到的對象使用add、remove方法可以使用如下解決辦法

List<String> pets = new ArrayList<String>(Arrays.asList("a", "b", "c")); 

問題三:上代碼

public class ArraysAsListTest {

  public static void main(String[] args) {
    String[] test
= {"a","b","c","d","e"};     List<String> testList = Arrays.asList(test);     System.out.println("list原始順序:"+testList);     //洗牌打亂list中元素順序 使用Collections.shuffled方法     Collections.shuffle(testList, new Random(2));     System.out.println("list打亂后順序:"+testList);     //list順序打亂后 原數組會發生神馬???     System.out.println("list打亂順序后數組內容:"+Arrays.toString(test));     /*     * list原始順序:[a, b, c, d, e]     list打亂后順序:[e, a, c, b, d]     list打亂順序后數組內容:[e, a, c, b, d]     */   } }

哦,NO!!!我只是改變list的順序,然而數組順序卻也發生了變化,很多時候這並不是我們想要的。

這時候我們就要意識到Arrays.asList()產生的list對象會使用底層數組作為其物理實現,只要執行操作修改這個list就會修改原來的數組。要想不改變原來數組,就要在另一個容器中創建一個副本,寫法如下

List<String> testList = new ArrayList<String>(Arrays.asList(test));

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM