分析如下例子:
1 import java.util.Arrays;
2 import java.util.List;
3
4
5 public class Test {
6 public static void main(String[] args) {
7 Integer[] a = {0,1,2,3,4,5,6};
8 List<Integer> c = Arrays.asList(a);
9 for (Integer integer : c) {
10 System.out.println(integer);
11 }
12 c.add(7);
13 c.remove(0);
14
15 }
16 }
打印结果为:
0 1 2 3 4 5 6 Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:151) at java.util.AbstractList.add(AbstractList.java:89) at com.cys.collections.MapTest.main(MapTest.java:14)
查看Arrays.asList() 底层实现:
public static <T> List<T> asList(T... a) { return new ArrayList<T>(a); }
实现同样是ArrayList ! But,再向下看:
文件名: Arrays$ArrayList.class 表明ArrayList是一个Arrays 类的内部类,与我们平时使用的ArrayList 并不同;
它继承了一个抽象类AbstractList并使用该抽象类的add 和 remove方法:
public boolean add(E o) { add(size(), o); return true; } public void add(int index, E element) { throw new UnsupportedOperationException(); } public E remove(int index) { throw new UnsupportedOperationException(); }
全部抛出了一个UnsupportedOperationException 异常,说明该list不支持改变它长度的情况。
但是同样是数组实现的直接 new 的 ArrayList为什么就可以呢?
让我们看一看它的add 代码:
1 public boolean add(E o) {
2 ensureCapacity(size + 1); // Increments modCount!!
3 elementData[size++] = o;
4 return true;
5 }
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
这两个方法里面的第一行,均是确信当前容量是否能容下新增加的对象。
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; elementData = (E[])new Object[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, size); } }
此方法里,一旦发现容量不足,会自动扩充容量,新的大小是
int newCapacity = (oldCapacity * 3)/2 + 1
再通过拷贝方法,新new一个数组。
remove 就很简单了,就是单纯的删去一个位置上的数据,然后把后面的数据依次向前挪。
所以 new ArrayList 可以 remove 和add 。
题外话:
我们看到ArrayList 的扩充是原来的1.5倍+1,所以为了避免频繁扩充带来的扩充损耗,应当尽可能大的new ArrayList的初始长度,
但是太大的话,如果数据增长很慢,就会占用很多没用的内存,所以这个长度还是需要根据业务的实际情况,合理申请。
http://www.cnblogs.com/caoyusongnet/