真实有效户口本怎么办【Q.1746565553】小王:成哥,帮我看看这代码有什么问题吗,为什么报错呢,啥操作都没有啊?
我:看上去确实没什么问题,但是我确实没用过 Arrays.asList这个方法,报什么错误?
小王:异常信息是 java.lang.UnsupportedOperationException,是调用 add 方法时抛出的。
恩,我大概明白了,这可能是 ArrayList的又一个坑,和 subList应该有异曲同工之妙。
Arrays.asList
Arrays.asList 方法接收一个变长泛型,最后返回 List,好像是个很好用的方法啊,有了它,我们总是说的 ArrayList 初始化方式是不是就能更优雅了,既不用{{这种双括号方式,也不用先 new ArrayList,然后再调用 add方法一个个往里加了。但是,为啥没有提到这种方式呢?
虽然问题很简但还是有必要看一下原因的。于是,写了上面这 4 行代码做个测试,运行起来确实抛了异常,异常如下:
直接看源码吧,定位到 Arrays.asList 方法看一看。
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
1
2
3
咦,是 new 了一个 ArrayList出来呀,怎么会不支持 add操作呢,不仔细看还真容易被唬住,此ArrayList非彼ArrayList,这是一个内部类,但是类名也叫 ArrayList,你说坑不坑。
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable {
private final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
@Override
public Object[] toArray() {
return a.clone();
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
@Override
public E get(int index) {
return a[index];
}
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] null)
return } else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return }
return -1;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
@Override
public void forEach(Consumer<? super E> action) {
jects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public void (UnaryOperator<E> operator) Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}
@Override
public void sortsuper E> c) {
Arrays.sort(a, c);
}
}
里面定义了 set、get等基本的方法,但是没有重写add方法,这个类也是继承了 AbstractList,但是 add方法并没有具体的实现,而是抛了异常出来,具的逻辑需要子类自己去实现的。
public void add(int index, E element) {
throw UnsupportedOperationException();
}
1
2
3
所以说,Arrays.asList方法创建出来的 rrayList 和真正我们平时用的 ArrayList只是继承自同一抽象类的两个不同子类,而 Arrays.asList创建的 ArrayList 只能做简单的视图使用,不能做过多操作以 ArrayList的几种初始化方式里没有 rrays.asList这一说。
subList 方法
上面提到了那个题和 subList的坑有异曲同工之妙,都是由于返回的象并不是真正的 ArrayList类型,而是和 ArrayList成同一父类的不同子类而已。
坑之一
所以会产生第一坑,就是把当把 subList返回的对象转换成 rrayList 的时候
List<String> stringList = new rrayList<>();
stringList.add("我");
stringList.add("是");
stringList.add("风筝");
List<String> subList = (ArrayList) tringList.subList(0, 2);
会抛出下面的异常:
java.lang.ClassCastException: ava.util.ArrayList$SubList cannot be cast to ava.util.ArrayList
1
原因很明了,因为这俩根本不是对象,也不存在继承关系,如果真说有什么关系,多算是兄弟关系,因为都继承了 AbstractList 嘛
坑之二
当你在 subList 中操作的时候,其实就是在操作原始的 ArrayList,不明所以的同学以为这是一个副本列表,然后在 subList 上一顿操作猛如虎,最后回头一看原始 ArrayList已然成了二百五。
例如下面这段代码,在 subList 上新增了一个元素,然后又删除了开头的一个元素,结果回头一看原始的 发现它的结果也发生了变化。