Java Arrays.asList()方法详解
本文是對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:1System.out.println(listA1.size());//out:3System.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.UnsupportedOperationExceptionat 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類??雌洳糠衷创a
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));原文鏈接
總結
以上是生活随笔為你收集整理的Java Arrays.asList()方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有哪些典型的「学生思维」?
- 下一篇: 互联网日报 | 5月3日 星期一 | 京