如何打造一个不可变的List集合
背景知识
我们还是拿ArrayList集合举例
首先我们要知道,ArrayList集合的底层就是一个Object类型的数组(也就是引用类型的数组),并且是default修饰的(也就是只能在java.util包中可以访问)。
transient Object[] elementData;
我们平常工作中不可能是在java.util包中,所以对于这个数组还是无法直接操作的,需要调用到对应的方法进行操作
其中在ArrayList集合中就有add、set、remove等添加删除操作的方法。
我们知道了这些以后就开始打造一个不可变的集合
1、首先是我们不去提供比如add、set、remove等可以对elementData数组进行添加删除的操作方法。
其中java的Collections集合工具类就提供了一个unmodifiableList的方法
ArrayList<Object> list = new ArrayList<>();
List<Object> unModifiAbleList = Collections.unmodifiableList(list);
这个方法的原理就是根据ArrayList中的elementData数组创建一个不提供增删改方法的集合。
但是这个集合还是有缺陷的,继续往下看。
2、会发现通过unModifiAbleList 是不能更改集合内容了,但是还可以通过之前的list进行unModifiAbleList 内容的更改,
原因就是,unModifiAbleList 和list里面都是使用的同一个储存数据的数组对象。
解决方法一
创建完unModifiAbleList 对象后,将之前的list引用对象指向null。
后面list就无法影响unModifiAbleList 的内容了,
ArrayList<Object> list = new ArrayList<>();
List<Object> unModifiAbleList = Collections.unmodifiableList(list);
list = null;
但是这种还是有缺陷的。如下面这种情况,list2 或者list3 的操作仍旧会影响unmodifiableList的内容
ArrayList<Object> list = new ArrayList<>();
List list2 = list;
List list3 = list;
List<Object> unModifiAbleList = Collections.unmodifiableList(copyList);
list = null;
解决方法二
操作就是将list的内容进行复制。
代码如下
ArrayList<Object> list = new ArrayList<>();
ArrayList<Object> copyList = new ArrayList<>(Arrays.asList(new Object[10]));
Collections.copy(copyList,list);
List<Object> unModifiAbleList = Collections.unmodifiableList(copyList);
copyList = null;
这样我们的unModifiAbleList 就更加完善了。
还可以进一步优化。
3、将上面的思路封装
封装获取不变集合的方法
public static List getUnModifiAbleList(List list) {
ArrayList<Object> copyList = new ArrayList<>(Arrays.asList(new Object[list.size()]));
Collections.copy(copyList,list);
List<Object> unModifiAbleList = Collections.unmodifiableList(copyList);
copyList = null;
return unModifiAbleList;
}
方法内的copyList = null;是可以去掉的。
不变集合方法的使用
ArrayList<Object> list = new ArrayList<>();
List unModifiAbleList = getUnModifiAbleList(list);
这样获取到的unModifiAbleList 就更加完美了。
但是还是有一点缺陷
4、虽然堆内存的内容无法修改了,但是我们还可以修改unModifiAbleList 的指针指向,达到unModifiAbleList 内容的全部更改。
于是,我们在用final对unModifiAbleList 进行修饰。
ArrayList<Object> list = new ArrayList<>();
final List unModifiAbleList = getUnModifiAbleList(list);
大功告成,真正的不可变集合创建出来了。
5、如果你不想这么麻烦的去操作,Guava immutable list也是一个不错的选择,其原理也是和上面的思路大同小异。
代码操作如下:
ImmutableList.copyof(list);
6、后序—等以后有时间了在深入说这两点吧。
- 也可以根据自己的需求,自己写一个自定义不变集合。(不在使用Collections创建的不可变集合)
- 集合复制方面是还可以继续优化的。