Blog
Blog copied to clipboard
Arrays.asList踩坑记及源码分析
最近在使用Arrays.asList时又犯了一个低级的错误导致了运行时异常,所以有必要把这个点好好理解下。从踩过的2个坑开始分析。

踩过的2个坑
Arrays.asList列表转数组问题
详细可以看这篇文章,toArray 方法返回的依然是 Object[],但是与 java.util.ArrayList 不同的是这里底层存储是泛型类型的数组 privatefinalE[]a,所以保留了实际的类型。
Arrays.asList列表不能新增元素
Arrays.asList构造的是一个固定大小的列表,底层存储是泛型数组,不能新增元素,原因在后面源码分析部分会看到。
Arrays.asList列表源码分析
Arrays.asList返回的是一个Arrays的内部类ArrayList,很小巧。

其实这个内部类和java.util.ArrayList的外貌(类层次图)是一样的,只是实现不同而已。

接下来我们分析内部类ArrayList源码。
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) {// !! 支持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);
}
}
存储
使用泛型数组,并且原始数组不能为Null。
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
转换为数组
直接对数组a进行clone,所以保留了原始对象类型。
public Object[] toArray() {
return a.clone();
}
和java.util.ArrayList一样,如果使用带指定参数类型的toArray就不存在返回类型不匹配的问题。
新增元素
该实现没有覆写add方法,而自AbstractList继承而来的add方法默认会抛出UnsupportedOperationException.
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
Java8新特性的支持
- 列表分隔 Spliterator
- 迭代遍历消费 Consumer
- 使用一元操作符替换列表 UnaryOperator
总结及想法
- 遇到问题要善于总结,不放过任何一个学习的机会
- 直接问Arrays.asList特点可能知道,但是实际中可能不会注意,不思考状态下的编程不可取