学而时习之,不亦乐乎。
今天的主题是Arrays.asList(),返回的List(ArrayList),为什么不支持remove,add操作。
先上第一盘菜,跟着源码一步一步走
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
Arrays下的asList方法,返回的是一个ArrayList,发现此ArrayList非彼"ArrayList"。而是Arrays中一个私有静态内部类,划重点。
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
...
}
写一段代码来开始测试。
public static void main(String[] args) {
try {
List<String> integers = Arrays.asList("1","2", "3", "4");
System.out.println(integers.size());
boolean result = integers.remove("2");
System.out.println(integers.size());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
当调用remove("2"),由于此ArrayList没有重写,则去调用ArrayList---AbstractList---AbstractCollection的remove(Object)方法,看到会调用迭代器it的remove方法
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
而it.remove(),则会调用实现类的AbstractList内部迭代器Itr的remove(),最终会调用AbstractList的remove(int)方法,
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
AbstractList的remove(int),方法会直接抛出异常。
而且Arrays.asList()返回的时候,只能向上转型为LIst<Integer>,而不是Arrays的内部类ArrayList,静态私有的。
综上所述:Arrays.asList()返回的List(ArrayList)不能进行add,remove的原因就是,此ArrayList是java.util.Arrays下的,而不是java.util包下的,此ArrayList没有重写这个方法,不具备这个行为,调用remove时,父类里面会抛异常。
那实际中如何解决这个问题呢,进行remove,add呢,既然返回的是ArrayList,但是它和java.util下的ArrayList有共同的父类Collection,都实现了List接口,可以将Arrays.asList返回的ArrayList作为参数,传给java.util下的ArrayList带Collection参数的构造方法。
java.util下的ArrayList
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}