有時候我們需要將數(shù)組轉成List集合對象,這時我們可以使用java.util.Arrays的asList方法,例如:
String[] strArray = new String[] {"aaa", "bbb"};
List<String> strList = Arrays.asList(strArray);
將對轉換后的strList對象添加一個新的元素:strList.add(“ccc”);
執(zhí)行這段代碼,但是拋出如下異常信息:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
為什么會拋出異常,并且顯示不支持add方法了?
我們看看傳統(tǒng)的標準集合類ArrayList以及add用法:
ArrayList是java中標準的集合類,可以通過他創(chuàng)建一個list集合,并且他提供了add等方法可以添加、修改集合元素,例如:
List<String> strList = new ArrayList<String>();
strList.add("aaa");
strList.add("bbb");
strList.add("ccc");
System.out.println(strList);
輸出的結果:[aaa, bbb, ccc]
同樣是List對象,前者可以正常執(zhí)行,而后者卻執(zhí)行失敗,原因在于兩者的實現(xiàn)不同,從jdk的源碼可以得到相應的答案:
Arrays.asList方法的實現(xiàn):
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
是直接通過new出一個ArrayList對象完成,但是注意,這里的ArrayList并不是java.util.ArrayList對象,而是Arrays類里面自己實現(xiàn)的一個同名的ArrayList,大致的結構如下:
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;
}
…...
}
在內部創(chuàng)建了一個不可變的數(shù)組a(private final E[] a),但這并不能解決我們?yōu)槭裁床荒苓M行add操作,點開這個類的add方法實現(xiàn):
public boolean add(E e) {
add(size(), e);
return true;
}
程序內部調用了:
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
從這里可以看出,為什么會當我們使用add操作的時候回拋出UnsupportedOperationException異常了,因為這個ArrayList并沒有實現(xiàn)add方法。
來看一下java.util.ArrayList的add方法實現(xiàn):
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
可以看到其實它的內部也是通過一個數(shù)組對象完成的操作,但是在對數(shù)組進行操作之前,調用了ensureCapacityInternal方法,而該方法最終調用了一個grow方法,該方法的源碼如下:
private void grow(int minCapacity) {
…...
elementData = Arrays.copyOf(elementData, newCapacity);
}
而這個方法的主要目的就是,判斷是否需要新增一個新的數(shù)組將原先不能容下的所有數(shù)據(jù)移動到新數(shù)組里面。
在每次add的時候都會做一次這樣的判斷,這樣的數(shù)組移動如果比較頻繁,是非常消耗資源的,所有在使用ArrayList數(shù)組的時候需要注意以下的幾個問題:
- 在創(chuàng)建ArrayList數(shù)組的時候,根據(jù)你需要的數(shù)量判斷,所以在創(chuàng)建ArrayList的時候指定初始的List長度,例new ArrayList<String>(20);如果不指定,默認的list長度為10.
- ArrayList的add方法常常會引起性能問題,所以,如果需要頻繁的插入、刪除最好是換成LinkedList這種以鏈表方式實現(xiàn)的集合。