用Arrays.asList将数组转成集合后,它真的是集合了吗?
一. 从Demo出发
@Test
public void testAsList() {
String[] strs = new String[]{"1", "2", "3", "4"};
List<String> list = Arrays.asList(strs);
list.add("5");
for (String s : list) {
System.out.println(s);
}
}
我们预想的输出结果肯定是打印1,2,3,4,5。但是实际结果如下: 意思是add() 方法并不是支持的操作,但是这么一看就奇了怪了,我List 集合,不就是用add() 方法来添加元素的吗?有什么错?
@Test
public void testList(){
ArrayList<String> list = new ArrayList<>();
list.add("1");
for (String s : list) {
System.out.println(s);
}
}
结果如下: 两者唯一的区别就是,前者的List 是通过Arrays.asList() 方法,从数组转成而来的集合,那么我们后续来分析下这个方法到底做了什么,让生成的集合无法使用相关集合操作。
二. 分析Arrays.asList()
从最外层接口出发:
public class Arrays {
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
}
可以发现返回一个ArrayList ,但是需要注意的是,这里的ArrayList 指的是Arrays 类下面的一个静态内部类,而非java.util.ArrayList :
public class Arrays {
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
}
@Override
public Object[] toArray() {
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
}
@Override
public E get(int index) {
}
@Override
public E set(int index, E element) {
}
@Override
public int indexOf(Object o) {
}
@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) {
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
}
@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}
}
看看发现了什么,调用构造的时候,会将传进来的数组赋值给内部类ArrayList 的a 属性,而a 属性的类型是个数组。该内部类只是做了一个简单的适配过程,同时,内部类中并没有重写add() 方法,而底层毕竟是数组,所以调用的时候会抛出UnsupportedOperationException 异常。
实际上,在调用Arrays.asList()后,底层的引用地址依旧没有改变:
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
如果我们对数组进行值的修改,会发生什么?
@Test
public void testAsList() {
String[] strs = new String[]{"1", "2", "3", "4"};
List<String> list = Arrays.asList(strs);
strs[0] = "111";
for (String s : list) {
System.out.println(s);
}
}
输出结果如下: 从这个案例我们就能得出两个重要的结论,在使用Arrays.asList() 后:
- 转化而来的集合底层依旧是个数组。 (换汤不换药)
- 转化而来的集合和原数组,两者指向同一个地址。
|