Arrays.asList 为什么不能 add 或者 remove 而 ArrayList 可以

分析如下例子:

 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/

原文地址:https://www.cnblogs.com/caoyusongnet/p/5541772.html