List集合系列的坑。
今天的课程来学习List集合中有哪些坑。
·坑点1:ArrayList并非ArrayList。使用Arrays初始化了一个集合,并向集合中添加新元素,代码执行会打印什么结果?结果添加元素时报错:unsupport operate。明明初始化了List,为什么add操作报错?来看看源码,Arrays初始化的集合是其内部类ArrayList,内部类ArrayList不是我们所熟知的ArrayList,并且这个内部类没有提供增删操作。
·坑点2:挥之不去的引用。使用Arrays初始化集合时,入参是数组,如果集合初始化完成后,修改数组,集合中的元素会变化么?实验结果中可以看到集合和切片同时被修改了。来看看源码,Arrays的初始化调用了内部类ArrayList的构造函数,在构造函数中沿用的是引用,而不是复制,所以这里修改数组,集合也会被同步修改。
·坑点3:List的subList方法,能把你干失业。使用循环,向全局变量data中,添加1万个长度为1的List。程序结束后,data中保存的是1万个长度为1的List,真的是这样么?结果却报错:OOM。来看看源码,subList方法调用了内部类SubList的构造函数,在构造函数中记录了原集合和对应的偏移量,也就是说集合切片后还对原来的集合保留着引用。这会引起原来的集合始终不能被回收,最终导致OOM。
需要注意的是,使用subList切片后,如果对原集合进行修改(切片与原集合共同部分),也会引起切片集合的变化。
解决方案:万能的new ArrayList。针对以上问题,均可以使用java.util包下面的ArrayList来解决,也就是使用ArrayList的构造函数,对切片集合进行一次包装。来看看源码,ArrayList的构造函数中能够看出,集合对源数据是拷贝的方式,而不是引用。
今天的课程讲解就到这,所以?你懂我意思吧?