阿里Java开发手册剖析:
-
6.5【强制】ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException
-
6.8【强制】在subList场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException
-
6.9【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为 0 的空数组。
-
6.11【强制】使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法, 它的 add/remove
-
6.14【强制】不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式
-
6.16【推荐】集合泛型定义时,在 JDK7 及以上,使用 diamond 语法或全省略。 说明:菱形泛型,即 diamond,直接使用<>来指代前边已经指定的类型。
【强制】使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法, 它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。
asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配 器模式,只是转换接口,后台的数据仍是数组。
异常demo:
public static void main(String[] args) {
String[] str = new String[] { "A", "B" };
List list = Arrays.asList(str);
// 第一种情况:
list.add("C");
}
输出日志:
看下Arrays.asList(str)
源码可以知道,返回的ArrayList是Arrays的内部类,而且不对外提供。
public class Arrays {
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
/**
* @serial include
*/
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) {
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 i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
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) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public void replaceAll(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 sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}
}
这个ArrayList并没有add(e)
方法的实现:
class ArrayList<E> extends AbstractList<E>
所以add(e)
具体应该是AbstractList<E>
类中了:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
}
所以Arrays.ArrayList本身就是不支持add(e)
方法。
可以看到这个类中存储了Array对象
a
,里面的一些修改的操作都是操作a
对象。比如public E set(int index, E element)
:
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
所以对
Arrays.asList(a)
返回对象的修改操作都会导致原有的Array数据同步修改。同时修改原有数组也会导致返回对象改变:
测试demo:
public static void main(String[] args) {
String[] str = new String[] { "A", "B" };
List list = Arrays.asList(str);
list.set(0,"C");
System.out.println("String[] str :");
for (String s : str) {
System.out.println(s);
}
System.out.println("Arrays.ArrayList :");
str[1]="D";
for (Object o : list) {
System.out.println(o);
}
}
日志输出:
String[] str :
C
B
Arrays.ArrayList :
C
D
Process finished with exit code 0