首页 > 代码库 > Collections.unmodifiableMap
Collections.unmodifiableMap
1. Collections.unmodifiableMap 是什么?
Java的官方解释:
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)
翻译过来就是:该方法返回了一个map的不可修改的视图umap, 为用户提供了一种生成只读容器的方法。如果尝试修改该容器umap, 将会抛出UnsupportedOperationException异常。
2. Collections.unmodifiableMap 能做什么?
在《重构-改善既有代码逻辑》一书中提到了封装集合的功能(Encapsulate Collection)。
我们在类中经常需要返回一个集合,比如mapA。如果直接返回成员变量mapA本身的话,相当于对外暴露了集合的引用,外部就可以随意修改该对象的集合,该对象可能对修改都一无所知,属性却发生了变化。
一种解决方法,就是将该集合修饰为private, 在返回集合的方法中采用Collections.unmodifiableMap(mapA),返回mapA的一个不可变的副本。且该方法要比我们自己去复制一个副本效率要高。
3. Collections.unmodifiableMap 构造的map真的不可修改吗?
遗憾的是该结论并不总是成立。对于map<key, value>中的内容value, unmodifiableMap仅仅保证的是它的引用不能被修改,如果value对应的是一个可变对象,那么该unmodifiableMap的内容还是可变的。见实例:
1 public class UnmodifiableMap { 2 3 public static void main(String[] args) { 4 5 Map<String, Student> map = new HashMap<String, Student>(); 6 Student tom = new Student("tom", 3); 7 map.put("tom", tom); 8 map.put("jerry", new Student("jerry", 1)); 9 10 Map<String, Student> unmodifiableMap = Collections.unmodifiableMap(map);11 // unmodifiableMap.put("tom", new Student("tom", 11)); // tag112 tom.setAge(11); // tag213 System.out.println(unmodifiableMap);14 }15 16 }17 18 // mutable19 class Student {20 private String name;21 private int age;22 23 public Student(String name, int age) {24 this.name = name;25 this.age = age;26 }27 28 public String getName() {29 return name;30 }31 32 public void setName(String name) {33 this.name = name;34 }35 36 public int getAge() {37 return age;38 }39 40 public void setAge(int age) {41 this.age = age;42 }43 44 @Override45 public String toString() {46 return "Student{" +47 "name=‘" + name + ‘\‘‘ +48 ", age=" + age +49 ‘}‘;50 }51 }
代码中Student 对象是可变对象。在tag1处,尝试更换为另一个对象,引用发生了变化,会抛出UnsupportedOperationException异常。unmodifiableMap阻止了对其的修改
但如果引用不变,见tag2处,还是tom, 但对该对象内容作了修改,unmodifiableMap并未阻止该行为。unmodifiableMap的内容变为了
{jerry=Student{name=‘jerry‘, age=1}, tom=Student{name=‘tom‘, age=11}}
所以为了线程安全,在使用Collections.unmodifiableMap的同时,尽量让其中的内容实现为不可变对象。
Collections.unmodifiableMap