什么是不可变容器
Java为用户提供了三种常用的容器:List
,Set
和Map
,并提供了对容器的各种操作——添加元素,修改元素,删除元素等等。但这几种容器都是可变的(mutable),即容器中的内容是可以改变的。
与可变容器相对的,就是不可变(immutable)容器,immutable意味着一个类的实例中的内容是不可变的,想要改变只能创建一个新的实例。
为什么需要不可变容器
可变性由于能够直接修改容器的内容,操作方便,效率也高,但却带来了很大的安全隐患——容器的内容可能在不经意间被改变,这种不经意的改变可能会给程序的正常运行带来灾难性的后果。考虑到这一点,Java在Collections类中提供了将以上三种容器包装为不可变容器的方法Collections.unmodifiableList(List<? extends T> list)
,Collections.unmodifiableSet(Set<? extends T> s)
和Collections.unmodifiableMap(Map<? extends K, ? extends V> m)
。以List
为例说明如何将可变的容器包装为一个不可变容器
List<Integer> testList = new ArrayList<>(); // 创建一个新的List
List<Integer> testUnmodifiableList = Collections.unmodifiableList(testList); // 将可变List包装为不可变List
不可变容器的具体实现
通过阅读源码,我们来进一步了解不可变容器是如何实现的。(以List
为例)
首先,Collections
类中有一个内部类UnmodifiableCollection
,给出其源码
static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
@java.io.Serial
private static final long serialVersionUID = 1820017752578914078L;
@SuppressWarnings("serial") // Conditionally serializable
final Collection<? extends E> c;
UnmodifiableCollection(Collection<? extends E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
}
public int size() {
return c.size();}
public boolean isEmpty() {
return c.isEmpty();}
public boolean contains(Object o) {
return c.contains(o);}
public Object[] toArray() {
return c.toArray();}
public <T> T[] toArray(T[] a) {
return c.toArray(a);}
public <T> T[] toArray(IntFunction<T[]> f) {
return c.toArray(f);}
public String toString() {
return c.toString();}
public Iterator<E> iterator() {
return new Iterator<E>() {
private final Iterator<? extends E> i = c.iterator();
public boolean hasNext() {
return i.hasNext();}
public E next() {
return i.next();}
public void remove() {