网站首页 > 基础教程 正文
1、问题背景
今天,在学员毕业群里,几位同学在讨论工作中遇到的一个坑,就是使用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方法来获取,这一点就类似咱们数据库的视图,你对这个集合元素的修改将会影响到数组中本来的元素。如下代码所示:
猜你喜欢
- 2024-10-12 Java中Array,List,Set,ArrayList,Linkedlist集合的区别
- 2024-10-12 Array与ArrayList的区别 arraylist和arrays
- 2024-10-12 面试官和我聊一聊 ArrayList 面试redis
- 2024-10-12 ArrayList 和 LinkedList 源码分析
- 2024-10-12 Java集合框架,我花60分钟总结,你花20分钟记忆
- 2024-10-12 ArrayList 源码浅析 arraylist源码分析
- 2024-10-12 学点算法(一)——ArrayList内部数组实现元素去重
- 2024-10-12 面试官让我聊聊 ArrayList 解决了数组的哪些问题
- 2024-10-12 秋招啦!朋友,你不会现在连泛型都不清楚吧!不会吧不会吧
- 2024-10-12 每天一道面试题之Arraylist 与 LinkedList 区别
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)