专业编程基础技术教程

网站首页 > 基础教程 正文

Arrays.asList方法解析 arraylist全部方法

ccvgpt 2024-10-12 14:05:29 基础教程 9 ℃

1、问题背景

今天,在学员毕业群里,几位同学在讨论工作中遇到的一个坑,就是使用Arrays.asList(数组参数)将一个数组转换为集合后,居然不能删除和添加。具体如下图:

这个问题一般我会在ArrayList的源码分析中插入一段解析,在这里再用文章的形式分享一下,便于后面查阅。

Arrays.asList方法解析 arraylist全部方法

2、原因分析

这个问题其实比较好分析,首先,从错误的堆栈信息可以看到,错误是在AbstractList这个类里面发生的,

at java.util.AbstractList.add(AbstractList.java:148),可以直接点开源码查看,发现源码的add方法其实直接抛出了不支持操作的异常:

public void add(int index, E element) { throw new UnsupportedOperationException(); }

那么,为什么是这样的效果呢?

让我们来跟踪源码看一看:

我们使用List<String> list = Arrays.asList(names);来将一个数组转换成了一个集合,得到的是一个父接口的集合。点开源码:

public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }

你会发现这个方法直接使用我们给的数组创建了一个ArrayList集合给我们,看到这里,有些小伙伴可能会被误导,ArrayList我知道啊,里面的增删改查代码我都看过无数次了。先不要着急,此ArrayList非彼ArrayList。再跟踪ArrayList类,你会发现,这个ArrayList其实是Arrays工具类的一个静态内部类:

private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {

private final E[] a;//这个内部类的数组实现使用了final修饰,导致这个数组不可变长 ArrayList(E[] array) { a = Objects.requireNonNull(array); }

//省略此处代码

}

这个类继承了AbstractList,AbstractList是一个抽象类,实现了List接口:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>{

//省略代码

}

看到这里,大家应该明白了,Arrays.asList返给我们的是一个静态内部类的对象。咱们翻看这个静态内部类的ArrayList发现,这个类里面并没有重写add和remove方法,但是我们知道List接口规定了add和remove方法,所以唯一的答案就是他的这个抽象父类实现了add和remove方法,而正如前文所言,在抽象父类AbstractList中,实现的add和remove方法仅仅是简单粗暴的抛出了UnsupportedOperationException异常而已。

3、扩展

注意,Arrays.asList方法如果传入的是基本数据类型的数组,不会自动装箱,而是会把这个数组当做一个元素存到集合里。另外虽然Arrays$ArrayList这个内部类里面的实现E[]数组有final修饰,但是这个数组里面的元素是可以修改的,他提供了get和set方法来获取,这一点就类似咱们数据库的视图,你对这个集合元素的修改将会影响到数组中本来的元素。如下代码所示:



Tags:

最近发表
标签列表